diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index 0a2c891c0..1ba452275 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -105,6 +105,7 @@ def run(["gen" | rest]) do
)
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
+ signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
{web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)
result_config =
@@ -120,6 +121,7 @@ def run(["gen" | rest]) do
dbpass: dbpass,
version: Pleroma.Mixfile.project() |> Keyword.get(:version),
secret: secret,
+ signing_salt: signing_salt,
web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),
web_push_private_key: Base.url_encode64(web_push_private_key, padding: false)
)
diff --git a/lib/mix/tasks/pleroma/sample_config.eex b/lib/mix/tasks/pleroma/sample_config.eex
index 740b9f8d1..1c935c0d8 100644
--- a/lib/mix/tasks/pleroma/sample_config.eex
+++ b/lib/mix/tasks/pleroma/sample_config.eex
@@ -7,7 +7,8 @@ use Mix.Config
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "<%= domain %>", scheme: "https", port: <%= port %>],
- secret_key_base: "<%= secret %>"
+ secret_key_base: "<%= secret %>",
+ signing_salt: "<%= signing_salt %>"
config :pleroma, :instance,
name: "<%= name %>",
diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
index 1dccdadae..c3c0384d2 100644
--- a/lib/pleroma/PasswordResetToken.ex
+++ b/lib/pleroma/PasswordResetToken.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.PasswordResetToken do
alias Pleroma.{User, PasswordResetToken, Repo}
schema "password_reset_tokens" do
- belongs_to(:user, User)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
field(:token, :string)
field(:used, :boolean, default: false)
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 8fd0311d2..f0aa3ce97 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Activity do
import Ecto.Query
@type t :: %__MODULE__{}
+ @primary_key {:id, Pleroma.FlakeId, autogenerate: true}
# https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19
@mastodon_notification_types %{
@@ -40,25 +41,7 @@ def get_by_id(id) do
Repo.get(Activity, id)
end
- # TODO:
- # Go through these and fix them everywhere.
- # Wrong name, only returns create activities
- def all_by_object_ap_id_q(ap_id) do
- from(
- activity in Activity,
- where:
- fragment(
- "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
- activity.data,
- activity.data,
- ^to_string(ap_id)
- ),
- where: fragment("(?)->>'type' = 'Create'", activity.data)
- )
- end
-
- # Wrong name, returns all.
- def all_non_create_by_object_ap_id_q(ap_id) do
+ def by_object_ap_id(ap_id) do
from(
activity in Activity,
where:
@@ -71,12 +54,7 @@ def all_non_create_by_object_ap_id_q(ap_id) do
)
end
- # Wrong name plz fix thx
- def all_by_object_ap_id(ap_id) do
- Repo.all(all_by_object_ap_id_q(ap_id))
- end
-
- def create_activity_by_object_id_query(ap_ids) do
+ def create_by_object_ap_id(ap_ids) when is_list(ap_ids) do
from(
activity in Activity,
where:
@@ -90,19 +68,37 @@ def create_activity_by_object_id_query(ap_ids) do
)
end
- def get_create_activity_by_object_ap_id(ap_id) when is_binary(ap_id) do
- create_activity_by_object_id_query([ap_id])
+ def create_by_object_ap_id(ap_id) do
+ from(
+ activity in Activity,
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
+ activity.data,
+ ^to_string(ap_id)
+ ),
+ where: fragment("(?)->>'type' = 'Create'", activity.data)
+ )
+ end
+
+ def get_all_create_by_object_ap_id(ap_id) do
+ Repo.all(create_by_object_ap_id(ap_id))
+ end
+
+ def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do
+ create_by_object_ap_id(ap_id)
|> Repo.one()
end
- def get_create_activity_by_object_ap_id(_), do: nil
+ def get_create_by_object_ap_id(_), do: nil
def normalize(obj) when is_map(obj), do: Activity.get_by_ap_id(obj["id"])
def normalize(ap_id) when is_binary(ap_id), do: Activity.get_by_ap_id(ap_id)
def normalize(_), do: nil
def get_in_reply_to_activity(%Activity{data: %{"object" => %{"inReplyTo" => ap_id}}}) do
- get_create_activity_by_object_ap_id(ap_id)
+ get_create_by_object_ap_id(ap_id)
end
def get_in_reply_to_activity(_), do: nil
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index ad2797209..47c0e5b68 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -99,6 +99,7 @@ def start(_type, _args) do
],
id: :cachex_idem
),
+ worker(Pleroma.FlakeId, []),
worker(Pleroma.Web.Federator.RetryQueue, []),
worker(Pleroma.Web.Federator, []),
worker(Pleroma.Stats, []),
diff --git a/lib/pleroma/clippy.ex b/lib/pleroma/clippy.ex
new file mode 100644
index 000000000..4e9bdbe19
--- /dev/null
+++ b/lib/pleroma/clippy.ex
@@ -0,0 +1,155 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Clippy do
+ @moduledoc false
+ # No software is complete until they have a Clippy implementation.
+ # A ballmer peak _may_ be required to change this module.
+
+ def tip() do
+ tips()
+ |> Enum.random()
+ |> puts()
+ end
+
+ def tips() do
+ host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
+
+ [
+ "“πλήρωμα” is “pleroma” in greek",
+ "For an extended Pleroma Clippy Experience, use the “Redmond” themes in Pleroma FE settings",
+ "Staff accounts and MRF policies of Pleroma instances are disclosed on the NodeInfo endpoints for easy transparency!\n
+- https://catgirl.science/misc/nodeinfo.lua?#{host}
+- https://fediverse.network/#{host}/federation",
+ "Pleroma can federate to the Dark Web!\n
+- Tor: https://git.pleroma.social/pleroma/pleroma/wikis/Easy%20Onion%20Federation%20(Tor)
+- i2p: https://git.pleroma.social/pleroma/pleroma/wikis/I2p%20federation",
+ "Lists of Pleroma instances:\n\n- http://distsn.org/pleroma-instances.html\n- https://fediverse.network/pleroma\n- https://the-federation.info/pleroma",
+ "Pleroma uses the LitePub protocol - https://litepub.social",
+ "To receive more federated posts, subscribe to relays!\n
+- How-to: https://git.pleroma.social/pleroma/pleroma/wikis/Admin%20tasks#relay-managment
+- Relays: https://fediverse.network/activityrelay"
+ ]
+ end
+
+ @spec puts(String.t() | [[IO.ANSI.ansicode() | String.t(), ...], ...]) :: nil
+ def puts(text_or_lines) do
+ import IO.ANSI
+
+ lines =
+ if is_binary(text_or_lines) do
+ String.split(text_or_lines, ~r/\n/)
+ else
+ text_or_lines
+ end
+
+ longest_line_size =
+ lines
+ |> Enum.map(&charlist_count_text/1)
+ |> Enum.sort(&>=/2)
+ |> List.first()
+
+ pad_text = longest_line_size
+
+ pad =
+ for(_ <- 1..pad_text, do: "_")
+ |> Enum.join("")
+
+ pad_spaces =
+ for(_ <- 1..pad_text, do: " ")
+ |> Enum.join("")
+
+ spaces = " "
+
+ pre_lines = [
+ " / \\#{spaces} _#{pad}___",
+ " | |#{spaces} / #{pad_spaces} \\"
+ ]
+
+ for l <- pre_lines do
+ IO.puts(l)
+ end
+
+ clippy_lines = [
+ " #{bright()}@ @#{reset()}#{spaces} ",
+ " || ||#{spaces}",
+ " || || <--",
+ " |\\_/| ",
+ " \\___/ "
+ ]
+
+ noclippy_line = " "
+
+ env = %{
+ max_size: pad_text,
+ pad: pad,
+ pad_spaces: pad_spaces,
+ spaces: spaces,
+ pre_lines: pre_lines,
+ noclippy_line: noclippy_line
+ }
+
+ # surrond one/five line clippy with blank lines around to not fuck up the layout
+ #
+ # yes this fix sucks but it's good enough, have you ever seen a release of windows wihtout some butched
+ # features anyway?
+ lines =
+ if length(lines) == 1 or length(lines) == 5 do
+ [""] ++ lines ++ [""]
+ else
+ lines
+ end
+
+ clippy_line(lines, clippy_lines, env)
+ rescue
+ e ->
+ IO.puts("(Clippy crashed, sorry: #{inspect(e)})")
+ IO.puts(text_or_lines)
+ end
+
+ defp clippy_line([line | lines], [prefix | clippy_lines], env) do
+ IO.puts([prefix <> "| ", rpad_line(line, env.max_size)])
+ clippy_line(lines, clippy_lines, env)
+ end
+
+ # more text lines but clippy's complete
+ defp clippy_line([line | lines], [], env) do
+ IO.puts([env.noclippy_line, "| ", rpad_line(line, env.max_size)])
+
+ if lines == [] do
+ IO.puts(env.noclippy_line <> "\\_#{env.pad}___/")
+ end
+
+ clippy_line(lines, [], env)
+ end
+
+ # no more text lines but clippy's not complete
+ defp clippy_line([], [clippy | clippy_lines], env) do
+ if env.pad do
+ IO.puts(clippy <> "\\_#{env.pad}___/")
+ clippy_line([], clippy_lines, %{env | pad: nil})
+ else
+ IO.puts(clippy)
+ clippy_line([], clippy_lines, env)
+ end
+ end
+
+ defp clippy_line(_, _, _) do
+ end
+
+ defp rpad_line(line, max) do
+ pad = max - (charlist_count_text(line) - 2)
+ pads = Enum.join(for(_ <- 1..pad, do: " "))
+ [IO.ANSI.format(line), pads <> " |"]
+ end
+
+ defp charlist_count_text(line) do
+ if is_list(line) do
+ text = Enum.join(Enum.filter(line, &is_binary/1))
+ String.length(text)
+ else
+ String.length(line)
+ end
+ end
+end
diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex
index df5374a5c..308bd70e1 100644
--- a/lib/pleroma/filter.ex
+++ b/lib/pleroma/filter.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.Filter do
alias Pleroma.{User, Repo}
schema "filters" do
- belongs_to(:user, User)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
field(:filter_id, :integer)
field(:hide, :boolean, default: false)
field(:whole_word, :boolean, default: true)
diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex
new file mode 100644
index 000000000..26399ae05
--- /dev/null
+++ b/lib/pleroma/flake_id.ex
@@ -0,0 +1,183 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.FlakeId do
+ @moduledoc """
+ Flake is a decentralized, k-ordered id generation service.
+
+ Adapted from:
+
+ * [flaky](https://github.com/nirvana/flaky), released under the terms of the Truly Free License,
+ * [Flake](https://github.com/boundary/flake), Copyright 2012, Boundary, Apache License, Version 2.0
+ """
+
+ @type t :: binary
+
+ @behaviour Ecto.Type
+ use GenServer
+ require Logger
+ alias __MODULE__
+ import Kernel, except: [to_string: 1]
+
+ defstruct node: nil, time: 0, sq: 0
+
+ @doc "Converts a binary Flake to a String"
+ def to_string(<<0::integer-size(64), id::integer-size(64)>>) do
+ Kernel.to_string(id)
+ end
+
+ def to_string(flake = <<_::integer-size(64), _::integer-size(48), _::integer-size(16)>>) do
+ encode_base62(flake)
+ end
+
+ def to_string(s), do: s
+
+ for i <- [-1, 0] do
+ def from_string(unquote(i)), do: <<0::integer-size(128)>>
+ def from_string(unquote(Kernel.to_string(i))), do: <<0::integer-size(128)>>
+ end
+
+ def from_string(flake = <<_::integer-size(128)>>), do: flake
+
+ def from_string(string) when is_binary(string) and byte_size(string) < 18 do
+ case Integer.parse(string) do
+ {id, _} -> <<0::integer-size(64), id::integer-size(64)>>
+ _ -> nil
+ end
+ end
+
+ def from_string(string) do
+ string |> decode_base62 |> from_integer
+ end
+
+ def to_integer(<>), do: integer
+
+ def from_integer(integer) do
+ <<_time::integer-size(64), _node::integer-size(48), _seq::integer-size(16)>> =
+ <>
+ end
+
+ @doc "Generates a Flake"
+ @spec get :: binary
+ def get, do: to_string(:gen_server.call(:flake, :get))
+
+ # -- Ecto.Type API
+ @impl Ecto.Type
+ def type, do: :uuid
+
+ @impl Ecto.Type
+ def cast(value) do
+ {:ok, FlakeId.to_string(value)}
+ end
+
+ @impl Ecto.Type
+ def load(value) do
+ {:ok, FlakeId.to_string(value)}
+ end
+
+ @impl Ecto.Type
+ def dump(value) do
+ {:ok, FlakeId.from_string(value)}
+ end
+
+ def autogenerate(), do: get()
+
+ # -- GenServer API
+ def start_link do
+ :gen_server.start_link({:local, :flake}, __MODULE__, [], [])
+ end
+
+ @impl GenServer
+ def init([]) do
+ {:ok, %FlakeId{node: mac(), time: time()}}
+ end
+
+ @impl GenServer
+ def handle_call(:get, _from, state) do
+ {flake, new_state} = get(time(), state)
+ {:reply, flake, new_state}
+ end
+
+ # Matches when the calling time is the same as the state time. Incr. sq
+ defp get(time, %FlakeId{time: time, node: node, sq: seq}) do
+ new_state = %FlakeId{time: time, node: node, sq: seq + 1}
+ {gen_flake(new_state), new_state}
+ end
+
+ # Matches when the times are different, reset sq
+ defp get(newtime, %FlakeId{time: time, node: node}) when newtime > time do
+ new_state = %FlakeId{time: newtime, node: node, sq: 0}
+ {gen_flake(new_state), new_state}
+ end
+
+ # Error when clock is running backwards
+ defp get(newtime, %FlakeId{time: time}) when newtime < time do
+ {:error, :clock_running_backwards}
+ end
+
+ defp gen_flake(%FlakeId{time: time, node: node, sq: seq}) do
+ <>
+ end
+
+ defp nthchar_base62(n) when n <= 9, do: ?0 + n
+ defp nthchar_base62(n) when n <= 35, do: ?A + n - 10
+ defp nthchar_base62(n), do: ?a + n - 36
+
+ defp encode_base62(<>) do
+ integer
+ |> encode_base62([])
+ |> List.to_string()
+ end
+
+ defp encode_base62(int, acc) when int < 0, do: encode_base62(-int, acc)
+ defp encode_base62(int, []) when int == 0, do: '0'
+ defp encode_base62(int, acc) when int == 0, do: acc
+
+ defp encode_base62(int, acc) do
+ r = rem(int, 62)
+ id = div(int, 62)
+ acc = [nthchar_base62(r) | acc]
+ encode_base62(id, acc)
+ end
+
+ defp decode_base62(s) do
+ decode_base62(String.to_charlist(s), 0)
+ end
+
+ defp decode_base62([c | cs], acc) when c >= ?0 and c <= ?9,
+ do: decode_base62(cs, 62 * acc + (c - ?0))
+
+ defp decode_base62([c | cs], acc) when c >= ?A and c <= ?Z,
+ do: decode_base62(cs, 62 * acc + (c - ?A + 10))
+
+ defp decode_base62([c | cs], acc) when c >= ?a and c <= ?z,
+ do: decode_base62(cs, 62 * acc + (c - ?a + 36))
+
+ defp decode_base62([], acc), do: acc
+
+ defp time do
+ {mega_seconds, seconds, micro_seconds} = :erlang.timestamp()
+ 1_000_000_000 * mega_seconds + seconds * 1000 + :erlang.trunc(micro_seconds / 1000)
+ end
+
+ def mac do
+ {:ok, addresses} = :inet.getifaddrs()
+
+ macids =
+ Enum.reduce(addresses, [], fn {_iface, attrs}, acc ->
+ case attrs[:hwaddr] do
+ [0, 0, 0 | _] -> acc
+ mac when is_list(mac) -> [mac_to_worker_id(mac) | acc]
+ _ -> acc
+ end
+ end)
+
+ List.first(macids)
+ end
+
+ def mac_to_worker_id(mac) do
+ <> = :binary.list_to_bin(mac)
+ worker
+ end
+end
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index 9e50ea3f4..386096a52 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -130,7 +130,7 @@ def add_links({subs, text}) do
end
@doc "Adds the links to mentioned users"
- def add_user_links({subs, text}, mentions) do
+ def add_user_links({subs, text}, mentions, options \\ []) do
mentions =
mentions
|> Enum.sort_by(fn {name, _} -> -String.length(name) end)
@@ -152,12 +152,16 @@ def add_user_links({subs, text}, mentions) do
ap_id
end
- short_match = String.split(match, "@") |> tl() |> hd()
+ nickname =
+ if options[:format] == :full do
+ User.full_nickname(match)
+ else
+ User.local_nickname(match)
+ end
{uuid,
- "@#{
- short_match
- }"}
+ "" <>
+ "@#{nickname}"}
end)
{subs, uuid_text}
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index a75dc006e..ca66c6916 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.List do
alias Pleroma.{User, Repo, Activity}
schema "lists" do
- belongs_to(:user, Pleroma.User)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
field(:title, :string)
field(:following, {:array, :string}, default: [])
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index c7d01f63b..2c8f60f19 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -9,8 +9,8 @@ defmodule Pleroma.Notification do
schema "notifications" do
field(:seen, :boolean, default: false)
- belongs_to(:user, Pleroma.User)
- belongs_to(:activity, Pleroma.Activity)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
+ belongs_to(:activity, Activity, type: Pleroma.FlakeId)
timestamps()
end
@@ -96,7 +96,7 @@ def dismiss(%{id: user_id} = _user, id) do
end
end
- def create_notifications(%Activity{id: _, data: %{"to" => _, "type" => type}} = activity)
+ def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity)
when type in ["Create", "Like", "Announce", "Follow"] do
users = get_notified_from_activity(activity)
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index ff5eb9b27..707a61f14 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -85,7 +85,7 @@ def swap_object_with_tombstone(object) do
def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object),
- Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
+ Repo.delete_all(Activity.by_object_ap_id(id)),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
{:ok, object}
end
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
index a3846c3bb..a25b5ea4e 100644
--- a/lib/pleroma/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy.ex
@@ -275,11 +275,24 @@ defp build_resp_headers(headers, opts) do
defp build_resp_cache_headers(headers, _opts) do
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
+ has_cache_control? = List.keymember?(headers, "cache-control", 0)
- if has_cache? do
- headers
- else
- List.keystore(headers, "cache-control", 0, {"cache-control", @default_cache_control_header})
+ cond do
+ has_cache? && has_cache_control? ->
+ headers
+
+ has_cache? ->
+ # There's caching header present but no cache-control -- we need to explicitely override it to public
+ # as Plug defaults to "max-age=0, private, must-revalidate"
+ List.keystore(headers, "cache-control", 0, {"cache-control", "public"})
+
+ true ->
+ List.keystore(
+ headers,
+ "cache-control",
+ 0,
+ {"cache-control", @default_cache_control_header}
+ )
end
end
diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex
index 108cf06b5..fbd89616c 100644
--- a/lib/pleroma/uploaders/s3.ex
+++ b/lib/pleroma/uploaders/s3.ex
@@ -9,12 +9,20 @@ defmodule Pleroma.Uploaders.S3 do
# The file name is re-encoded with S3's constraints here to comply with previous links with less strict filenames
def get_file(file) do
config = Pleroma.Config.get([__MODULE__])
+ bucket = Keyword.fetch!(config, :bucket)
+
+ bucket_with_namespace =
+ if namespace = Keyword.get(config, :bucket_namespace) do
+ namespace <> ":" <> bucket
+ else
+ bucket
+ end
{:ok,
{:url,
Path.join([
Keyword.fetch!(config, :public_endpoint),
- Keyword.fetch!(config, :bucket),
+ bucket_with_namespace,
strict_encode(URI.decode(file))
])}}
end
diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex
index 0959d7a3e..ce83cbbbc 100644
--- a/lib/pleroma/uploaders/uploader.ex
+++ b/lib/pleroma/uploaders/uploader.ex
@@ -27,18 +27,47 @@ defmodule Pleroma.Uploaders.Uploader do
This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL.
* `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity.
* `{:error, String.t}` error information if the file failed to be saved to the backend.
+ * `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method.
"""
+ @type file_spec :: {:file | :url, String.t()}
@callback put_file(Pleroma.Upload.t()) ::
- :ok | {:ok, {:file | :url, String.t()}} | {:error, String.t()}
+ :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
+
+ @callback http_callback(Plug.Conn.t(), Map.t()) ::
+ {:ok, Plug.Conn.t()}
+ | {:ok, Plug.Conn.t(), file_spec()}
+ | {:error, Plug.Conn.t(), String.t()}
+ @optional_callbacks http_callback: 2
+
+ @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
- @spec put_file(module(), Pleroma.Upload.t()) ::
- {:ok, {:file | :url, String.t()}} | {:error, String.t()}
def put_file(uploader, upload) do
case uploader.put_file(upload) do
:ok -> {:ok, {:file, upload.path}}
- other -> other
+ :wait_callback -> handle_callback(uploader, upload)
+ {:ok, _} = ok -> ok
+ {:error, _} = error -> error
+ end
+ end
+
+ defp handle_callback(uploader, upload) do
+ :global.register_name({__MODULE__, upload.path}, self())
+
+ receive do
+ {__MODULE__, pid, conn, params} ->
+ case uploader.http_callback(conn, params) do
+ {:ok, conn, ok} ->
+ send(pid, {__MODULE__, conn})
+ {:ok, ok}
+
+ {:error, conn, error} ->
+ send(pid, {__MODULE__, conn})
+ {:error, error}
+ end
+ after
+ 30_000 -> {:error, "Uploader callback timeout"}
end
end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 5137af917..1468cc133 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -17,6 +17,8 @@ defmodule Pleroma.User do
@type t :: %__MODULE__{}
+ @primary_key {:id, Pleroma.FlakeId, autogenerate: true}
+
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
@strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
@@ -35,7 +37,7 @@ defmodule Pleroma.User do
field(:avatar, :map)
field(:local, :boolean, default: true)
field(:follower_address, :string)
- field(:search_distance, :float, virtual: true)
+ field(:search_rank, :float, virtual: true)
field(:tags, {:array, :string}, default: [])
field(:last_refreshed_at, :naive_datetime)
has_many(:notifications, Notification)
@@ -473,8 +475,7 @@ def get_cached_by_nickname_or_id(nickname_or_id) do
def get_by_nickname(nickname) do
Repo.get_by(User, nickname: nickname) ||
if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do
- [local_nickname, _] = String.split(nickname, "@")
- Repo.get_by(User, nickname: local_nickname)
+ Repo.get_by(User, nickname: local_nickname(nickname))
end
end
@@ -537,6 +538,12 @@ def get_followers(user, page \\ nil) do
{:ok, Repo.all(q)}
end
+ def get_followers_ids(user, page \\ nil) do
+ q = get_followers_query(user, page)
+
+ Repo.all(from(u in q, select: u.id))
+ end
+
def get_friends_query(%User{id: id, following: following}, nil) do
from(
u in User,
@@ -561,6 +568,12 @@ def get_friends(user, page \\ nil) do
{:ok, Repo.all(q)}
end
+ def get_friends_ids(user, page \\ nil) do
+ q = get_friends_query(user, page)
+
+ Repo.all(from(u in q, select: u.id))
+ end
+
def get_follow_requests_query(%User{} = user) do
from(
a in Activity,
@@ -692,37 +705,120 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
Repo.all(query)
end
- def search(query, resolve \\ false) do
- # strip the beginning @ off if there is a query
+ def search(query, resolve \\ false, for_user \\ nil) do
+ # Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@")
- if resolve do
- User.get_or_fetch_by_nickname(query)
- end
+ if resolve, do: User.get_or_fetch_by_nickname(query)
- inner =
- from(
- u in User,
- select_merge: %{
- search_distance:
- fragment(
- "? <-> (? || coalesce(?, ''))",
- ^query,
- u.nickname,
- u.name
- )
- },
- where: not is_nil(u.nickname)
- )
+ fts_results = do_search(fts_search_subquery(query), for_user)
+ {:ok, trigram_results} =
+ Repo.transaction(fn ->
+ Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
+ do_search(trigram_search_subquery(query), for_user)
+ end)
+
+ Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
+ end
+
+ defp do_search(subquery, for_user, options \\ []) do
q =
from(
- s in subquery(inner),
- order_by: s.search_distance,
- limit: 20
+ s in subquery(subquery),
+ order_by: [desc: s.search_rank],
+ limit: ^(options[:limit] || 20)
)
- Repo.all(q)
+ results =
+ q
+ |> Repo.all()
+ |> Enum.filter(&(&1.search_rank > 0))
+
+ boost_search_results(results, for_user)
+ end
+
+ defp fts_search_subquery(query) do
+ processed_query =
+ query
+ |> String.replace(~r/\W+/, " ")
+ |> String.trim()
+ |> String.split()
+ |> Enum.map(&(&1 <> ":*"))
+ |> Enum.join(" | ")
+
+ from(
+ u in User,
+ select_merge: %{
+ search_rank:
+ fragment(
+ """
+ ts_rank_cd(
+ setweight(to_tsvector('simple', regexp_replace(?, '\\W', ' ', 'g')), 'A') ||
+ setweight(to_tsvector('simple', regexp_replace(coalesce(?, ''), '\\W', ' ', 'g')), 'B'),
+ to_tsquery('simple', ?),
+ 32
+ )
+ """,
+ u.nickname,
+ u.name,
+ ^processed_query
+ )
+ },
+ where:
+ fragment(
+ """
+ (setweight(to_tsvector('simple', regexp_replace(?, '\\W', ' ', 'g')), 'A') ||
+ setweight(to_tsvector('simple', regexp_replace(coalesce(?, ''), '\\W', ' ', 'g')), 'B')) @@ to_tsquery('simple', ?)
+ """,
+ u.nickname,
+ u.name,
+ ^processed_query
+ )
+ )
+ end
+
+ defp trigram_search_subquery(query) do
+ from(
+ u in User,
+ select_merge: %{
+ search_rank:
+ fragment(
+ "similarity(?, trim(? || ' ' || coalesce(?, '')))",
+ ^query,
+ u.nickname,
+ u.name
+ )
+ },
+ where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^query)
+ )
+ end
+
+ defp boost_search_results(results, nil), do: results
+
+ defp boost_search_results(results, for_user) do
+ friends_ids = get_friends_ids(for_user)
+ followers_ids = get_followers_ids(for_user)
+
+ Enum.map(
+ results,
+ fn u ->
+ search_rank_coef =
+ cond do
+ u.id in friends_ids ->
+ 1.2
+
+ u.id in followers_ids ->
+ 1.1
+
+ true ->
+ 1
+ end
+
+ Map.put(u, :search_rank, u.search_rank * search_rank_coef)
+ end
+ )
+ |> Enum.sort_by(&(-&1.search_rank))
end
def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do
@@ -833,7 +929,7 @@ def local_user_query do
def active_local_user_query do
from(
u in local_user_query(),
- where: fragment("?->'deactivated' @> 'false'", u.info)
+ where: fragment("not (?->'deactivated' @> 'true')", u.info)
)
end
@@ -1023,7 +1119,7 @@ def parse_bio(bio, user) do
end)
bio
- |> CommonUtils.format_input(mentions, tags, "text/plain")
+ |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full])
|> Formatter.emojify(emoji)
end
@@ -1074,6 +1170,16 @@ defp local_nickname_regex() do
end
end
+ def local_nickname(nickname_or_mention) do
+ nickname_or_mention
+ |> full_nickname()
+ |> String.split("@")
+ |> hd()
+ end
+
+ def full_nickname(nickname_or_mention),
+ do: String.trim_leading(nickname_or_mention, "@")
+
def error_user(ap_id) do
%User{
name: ap_id,
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index fb1791c20..c6c923aac 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.User.Info do
field(:hub, :string, default: nil)
field(:salmon, :string, default: nil)
field(:hide_network, :boolean, default: false)
- field(:pinned_activities, {:array, :integer}, default: [])
+ field(:pinned_activities, {:array, :string}, default: [])
# Found in the wild
# ap_id -> Where is this used?
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 5b87f7462..85fa83e2b 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -92,7 +92,7 @@ def insert(map, local \\ true) when is_map(map) do
def stream_out(activity) do
public = "https://www.w3.org/ns/activitystreams#Public"
- if activity.data["type"] in ["Create", "Announce"] do
+ if activity.data["type"] in ["Create", "Announce", "Delete"] do
Pleroma.Web.Streamer.stream("user", activity)
Pleroma.Web.Streamer.stream("list", activity)
@@ -103,16 +103,18 @@ def stream_out(activity) do
Pleroma.Web.Streamer.stream("public:local", activity)
end
- activity.data["object"]
- |> Map.get("tag", [])
- |> Enum.filter(fn tag -> is_bitstring(tag) end)
- |> Enum.map(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
+ if activity.data["type"] in ["Create"] do
+ activity.data["object"]
+ |> Map.get("tag", [])
+ |> Enum.filter(fn tag -> is_bitstring(tag) end)
+ |> Enum.map(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
- if activity.data["object"]["attachment"] != [] do
- Pleroma.Web.Streamer.stream("public:media", activity)
+ if activity.data["object"]["attachment"] != [] do
+ Pleroma.Web.Streamer.stream("public:media", activity)
- if activity.local do
- Pleroma.Web.Streamer.stream("public:local:media", activity)
+ if activity.local do
+ Pleroma.Web.Streamer.stream("public:local:media", activity)
+ end
end
end
else
@@ -138,8 +140,9 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d
additional
),
{:ok, activity} <- insert(create_data, local),
- :ok <- maybe_federate(activity),
- {:ok, _actor} <- User.increase_note_count(actor) do
+ # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
+ {:ok, _actor} <- User.increase_note_count(actor),
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@@ -224,10 +227,11 @@ def announce(
%User{ap_id: _} = user,
%Object{data: %{"id" => _}} = object,
activity_id \\ nil,
- local \\ true
+ local \\ true,
+ public \\ true
) do
with true <- is_public?(object),
- announce_data <- make_announce_data(user, object, activity_id),
+ announce_data <- make_announce_data(user, object, activity_id, public),
{:ok, activity} <- insert(announce_data, local),
{:ok, object} <- add_announce_to_object(activity, object),
:ok <- maybe_federate(activity) do
@@ -285,8 +289,9 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru
with {:ok, _} <- Object.delete(object),
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- {:ok, _actor} <- User.decrease_note_count(user) do
+ # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
+ {:ok, _actor} <- User.decrease_note_count(user),
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@@ -405,6 +410,8 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do
|> Enum.reverse()
end
+ defp restrict_since(query, %{"since_id" => ""}), do: query
+
defp restrict_since(query, %{"since_id" => since_id}) do
from(activity in query, where: activity.id > ^since_id)
end
@@ -460,6 +467,8 @@ defp restrict_local(query, %{"local_only" => true}) do
defp restrict_local(query, _), do: query
+ defp restrict_max(query, %{"max_id" => ""}), do: query
+
defp restrict_max(query, %{"max_id" => max_id}) do
from(activity in query, where: activity.id < ^max_id)
end
@@ -796,13 +805,24 @@ def fetch_and_contain_remote_object_from_id(id) do
end
end
- def is_public?(%Object{data: %{"type" => "Tombstone"}}) do
- false
+ def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
+ def is_public?(%Object{data: data}), do: is_public?(data)
+ def is_public?(%Activity{data: data}), do: is_public?(data)
+ def is_public?(%{"directMessage" => true}), do: false
+
+ def is_public?(data) do
+ "https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || []))
end
- def is_public?(activity) do
- "https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++
- (activity.data["cc"] || []))
+ def is_private?(activity) do
+ !is_public?(activity) && Enum.any?(activity.data["to"], &String.contains?(&1, "/followers"))
+ end
+
+ def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true
+ def is_direct?(%Object{data: %{"directMessage" => true}}), do: true
+
+ def is_direct?(activity) do
+ !is_public?(activity) && !is_private?(activity)
end
def visible_for_user?(activity, nil) do
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
new file mode 100644
index 000000000..7c6ad582a
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
@@ -0,0 +1,57 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
+ alias Pleroma.User
+
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ # XXX: this should become User.normalize_by_ap_id() or similar, really.
+ defp normalize_by_ap_id(%{"id" => id}), do: User.get_cached_by_ap_id(id)
+ defp normalize_by_ap_id(uri) when is_binary(uri), do: User.get_cached_by_ap_id(uri)
+ defp normalize_by_ap_id(_), do: nil
+
+ defp score_nickname("followbot@" <> _), do: 1.0
+ defp score_nickname("federationbot@" <> _), do: 1.0
+ defp score_nickname("federation_bot@" <> _), do: 1.0
+ defp score_nickname(_), do: 0.0
+
+ defp score_displayname("federation bot"), do: 1.0
+ defp score_displayname("federationbot"), do: 1.0
+ defp score_displayname("fedibot"), do: 1.0
+ defp score_displayname(_), do: 0.0
+
+ defp determine_if_followbot(%User{nickname: nickname, name: displayname}) do
+ nick_score =
+ nickname
+ |> String.downcase()
+ |> score_nickname()
+
+ name_score =
+ displayname
+ |> String.downcase()
+ |> score_displayname()
+
+ nick_score + name_score
+ end
+
+ defp determine_if_followbot(_), do: 0.0
+
+ @impl true
+ def filter(%{"type" => "Follow", "actor" => actor_id} = message) do
+ %User{} = actor = normalize_by_ap_id(actor_id)
+
+ score = determine_if_followbot(actor)
+
+ # TODO: scan biography data for keywords and score it somehow.
+ if score < 0.8 do
+ {:ok, message}
+ else
+ {:reject, nil}
+ end
+ end
+
+ @impl true
+ def filter(message), do: {:ok, message}
+end
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index abddbc790..c0a52e349 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -40,7 +40,7 @@ def unfollow(target_instance) do
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(),
%Object{} = object <- Object.normalize(activity.data["object"]["id"]) do
- ActivityPub.announce(user, object)
+ ActivityPub.announce(user, object, nil, true, false)
else
e -> Logger.error("error: #{inspect(e)}")
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 86d11c874..6656a11c6 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -93,12 +93,47 @@ def fix_addressing_list(map, field) do
end
end
- def fix_addressing(map) do
- map
+ def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, explicit_mentions) do
+ explicit_to =
+ to
+ |> Enum.filter(fn x -> x in explicit_mentions end)
+
+ explicit_cc =
+ to
+ |> Enum.filter(fn x -> x not in explicit_mentions end)
+
+ final_cc =
+ (cc ++ explicit_cc)
+ |> Enum.uniq()
+
+ object
+ |> Map.put("to", explicit_to)
+ |> Map.put("cc", final_cc)
+ end
+
+ def fix_explicit_addressing(object, _explicit_mentions), do: object
+
+ # if directMessage flag is set to true, leave the addressing alone
+ def fix_explicit_addressing(%{"directMessage" => true} = object), do: object
+
+ def fix_explicit_addressing(object) do
+ explicit_mentions =
+ object
+ |> Utils.determine_explicit_mentions()
+
+ explicit_mentions = explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public"]
+
+ object
+ |> fix_explicit_addressing(explicit_mentions)
+ end
+
+ def fix_addressing(object) do
+ object
|> fix_addressing_list("to")
|> fix_addressing_list("cc")
|> fix_addressing_list("bto")
|> fix_addressing_list("bcc")
+ |> fix_explicit_addressing
end
def fix_actor(%{"attributedTo" => actor} = object) do
@@ -141,7 +176,7 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object)
case fetch_obj_helper(in_reply_to_id) do
{:ok, replied_object} ->
with %Activity{} = activity <-
- Activity.get_create_activity_by_object_ap_id(replied_object.data["id"]) do
+ Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
object
|> Map.put("inReplyTo", replied_object.data["id"])
|> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
@@ -334,7 +369,7 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj
Map.put(data, "actor", actor)
|> fix_addressing
- with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]),
+ with nil <- Activity.get_create_by_object_ap_id(object["id"]),
%User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do
object = fix_object(data["object"])
@@ -348,6 +383,7 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj
additional:
Map.take(data, [
"cc",
+ "directMessage",
"id"
])
}
@@ -451,7 +487,8 @@ def handle_incoming(
with actor <- get_actor(data),
%User{} = actor <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
- {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do
+ public <- ActivityPub.is_public?(data),
+ {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do
{:ok, activity}
else
_e -> :error
@@ -863,15 +900,10 @@ defp user_upgrade_task(user) do
maybe_retire_websub(user.ap_id)
- # Only do this for recent activties, don't go through the whole db.
- # Only look at the last 1000 activities.
- since = (Repo.aggregate(Activity, :max, :id) || 0) - 1_000
-
q =
from(
a in Activity,
where: ^old_follower_address in a.recipients,
- where: a.id > ^since,
update: [
set: [
recipients:
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 6ecab773c..e40d05fcd 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -25,6 +25,20 @@ def normalize_params(params) do
Map.put(params, "actor", get_ap_id(params["actor"]))
end
+ def determine_explicit_mentions(%{"tag" => tag} = _object) when is_list(tag) do
+ tag
+ |> Enum.filter(fn x -> is_map(x) end)
+ |> Enum.filter(fn x -> x["type"] == "Mention" end)
+ |> Enum.map(fn x -> x["href"] end)
+ end
+
+ def determine_explicit_mentions(%{"tag" => tag} = object) when is_map(tag) do
+ Map.put(object, "tag", [tag])
+ |> determine_explicit_mentions()
+ end
+
+ def determine_explicit_mentions(_), do: []
+
defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll
defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll
defp recipient_in_collection(_, _), do: false
@@ -198,7 +212,7 @@ def update_object_in_activities(%{data: %{"id" => id}} = object) do
# Update activities that already had this. Could be done in a seperate process.
# Alternatively, just don't do this and fetch the current object each time. Most
# could probably be taken from cache.
- relevant_activities = Activity.all_by_object_ap_id(id)
+ relevant_activities = Activity.get_all_create_by_object_ap_id(id)
Enum.map(relevant_activities, fn activity ->
new_activity_data = activity.data |> Map.put("object", object.data)
@@ -386,9 +400,10 @@ def get_existing_announce(actor, %{data: %{"id" => id}}) do
"""
# for relayed messages, we only want to send to subscribers
def make_announce_data(
- %User{ap_id: ap_id, nickname: nil} = user,
+ %User{ap_id: ap_id} = user,
%Object{data: %{"id" => id}} = object,
- activity_id
+ activity_id,
+ false
) do
data = %{
"type" => "Announce",
@@ -405,7 +420,8 @@ def make_announce_data(
def make_announce_data(
%User{ap_id: ap_id} = user,
%Object{data: %{"id" => id}} = object,
- activity_id
+ activity_id,
+ true
) do
data = %{
"type" => "Announce",
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index fe8248107..dcf681b6d 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -160,7 +160,7 @@ def render("outbox.json", %{user: user, max_id: max_qid}) do
"partOf" => iri,
"totalItems" => info.note_count,
"orderedItems" => collection,
- "next" => "#{iri}?max_id=#{min_id - 1}"
+ "next" => "#{iri}?max_id=#{min_id}"
}
if max_qid == nil do
@@ -207,7 +207,7 @@ def render("inbox.json", %{user: user, max_id: max_qid}) do
"partOf" => iri,
"totalItems" => -1,
"orderedItems" => collection,
- "next" => "#{iri}?max_id=#{min_id - 1}"
+ "next" => "#{iri}?max_id=#{min_id}"
}
if max_qid == nil do
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 504670439..7084da6de 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -143,7 +143,7 @@ def post(user, %{"status" => status} = data) do
actor: user,
context: context,
object: object,
- additional: %{"cc" => cc}
+ additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
})
res
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 7e30d224c..a0f59d900 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -14,13 +14,13 @@ defmodule Pleroma.Web.CommonAPI.Utils do
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
+ activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
activity &&
if activity.data["type"] == "Create" do
activity
else
- Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ Activity.get_create_by_object_ap_id(activity.data["object"])
end
end
@@ -116,16 +116,18 @@ def add_attachments(text, attachments) do
Enum.join([text | attachment_text], "
")
end
+ def format_input(text, mentions, tags, format, options \\ [])
+
@doc """
Formatting text to plain text.
"""
- def format_input(text, mentions, tags, "text/plain") do
+ def format_input(text, mentions, tags, "text/plain", options) do
text
|> Formatter.html_escape("text/plain")
|> String.replace(~r/\r?\n/, "
")
|> (&{[], &1}).()
|> Formatter.add_links()
- |> Formatter.add_user_links(mentions)
+ |> Formatter.add_user_links(mentions, options[:user_links] || [])
|> Formatter.add_hashtag_links(tags)
|> Formatter.finalize()
end
@@ -133,24 +135,24 @@ def format_input(text, mentions, tags, "text/plain") do
@doc """
Formatting text to html.
"""
- def format_input(text, mentions, _tags, "text/html") do
+ def format_input(text, mentions, _tags, "text/html", options) do
text
|> Formatter.html_escape("text/html")
|> (&{[], &1}).()
- |> Formatter.add_user_links(mentions)
+ |> Formatter.add_user_links(mentions, options[:user_links] || [])
|> Formatter.finalize()
end
@doc """
Formatting text to markdown.
"""
- def format_input(text, mentions, tags, "text/markdown") do
+ def format_input(text, mentions, tags, "text/markdown", options) do
text
|> Formatter.mentions_escape(mentions)
|> Earmark.as_html!()
|> Formatter.html_escape("text/html")
|> (&{[], &1}).()
- |> Formatter.add_user_links(mentions)
+ |> Formatter.add_user_links(mentions, options[:user_links] || [])
|> Formatter.add_hashtag_links(tags)
|> Formatter.finalize()
end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index daad89185..f4736fcb5 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -377,7 +377,7 @@ def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -386,7 +386,7 @@ def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -395,7 +395,7 @@ def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -743,8 +743,7 @@ def status_search(user, query) do
fetched =
if Regex.match?(~r/https?:/, query) do
with {:ok, object} <- ActivityPub.fetch_object_from_id(query),
- %Activity{} = activity <-
- Activity.get_create_activity_by_object_ap_id(object.data["id"]),
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
true <- ActivityPub.visible_for_user?(activity, user) do
[activity]
else
@@ -771,7 +770,7 @@ def status_search(user, query) do
end
def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true")
+ accounts = User.search(query, params["resolve"] == "true", user)
statuses = status_search(user, query)
@@ -795,7 +794,7 @@ def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
end
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true")
+ accounts = User.search(query, params["resolve"] == "true", user)
statuses = status_search(user, query)
@@ -816,7 +815,7 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
end
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true")
+ accounts = User.search(query, params["resolve"] == "true", user)
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
@@ -1138,7 +1137,7 @@ def empty_object(conn, _) do
def render_notification(user, %{id: id, activity: activity, inserted_at: created_at} = _params) do
actor = User.get_cached_by_ap_id(activity.data["actor"])
- parent_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
mastodon_type = Activity.mastodon_notification_type(activity)
response = %{
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 7f5a52ea3..7a384e941 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -25,7 +25,7 @@ defp get_replied_to_activities(activities) do
nil
end)
|> Enum.filter(& &1)
- |> Activity.create_activity_by_object_id_query()
+ |> Activity.create_by_object_ap_id()
|> Repo.all()
|> Enum.reduce(%{}, fn activity, acc ->
Map.put(acc, activity.data["object"]["id"], activity)
@@ -64,7 +64,7 @@ def render(
user = get_user(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"])
- reblogged = Activity.get_create_activity_by_object_ap_id(object)
+ reblogged = Activity.get_create_by_object_ap_id(object)
reblogged = render("status.json", Map.put(opts, :activity, reblogged))
mentions =
@@ -209,7 +209,7 @@ def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
def get_reply_to(%{data: %{"object" => object}}, _) do
if object["inReplyTo"] && object["inReplyTo"] != "" do
- Activity.get_create_activity_by_object_ap_id(object["inReplyTo"])
+ Activity.get_create_by_object_ap_id(object["inReplyTo"])
else
nil
end
@@ -231,6 +231,9 @@ def get_visibility(object) do
Enum.any?(to, &String.contains?(&1, "/followers")) ->
"private"
+ length(cc) > 0 ->
+ "private"
+
true ->
"direct"
end
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
index cc4b74bc5..f8c65602d 100644
--- a/lib/pleroma/web/oauth/authorization.ex
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
field(:token, :string)
field(:valid_until, :naive_datetime)
field(:used, :boolean, default: false)
- belongs_to(:user, Pleroma.User)
+ belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
belongs_to(:app, App)
timestamps()
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index f0ebc63f6..4e01b123b 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.OAuth.Token do
field(:token, :string)
field(:refresh_token, :string)
field(:valid_until, :naive_datetime)
- belongs_to(:user, Pleroma.User)
+ belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
belongs_to(:app, App)
timestamps()
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index 94b1a7ad1..3d41fc708 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -183,7 +183,7 @@ def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_autho
_in_reply_to = get_in_reply_to(activity.data)
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
- retweeted_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ retweeted_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"])
retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true)
diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex
index 5aeed46f0..c5b3e8d97 100644
--- a/lib/pleroma/web/ostatus/handlers/note_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex
@@ -86,7 +86,7 @@ def add_external_url(note, entry) do
end
def fetch_replied_to_activity(entry, inReplyTo) do
- with %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(inReplyTo) do
+ with %Activity{} = activity <- Activity.get_create_by_object_ap_id(inReplyTo) do
activity
else
_e ->
@@ -103,7 +103,7 @@ def fetch_replied_to_activity(entry, inReplyTo) do
# TODO: Clean this up a bit.
def handle_note(entry, doc \\ nil) do
with id <- XML.string_from_xpath("//id", entry),
- activity when is_nil(activity) <- Activity.get_create_activity_by_object_ap_id(id),
+ activity when is_nil(activity) <- Activity.get_create_by_object_ap_id(id),
[author] <- :xmerl_xpath.string('//author[1]', doc),
{:ok, actor} <- OStatus.find_make_or_update_user(author),
content_html <- OStatus.get_content(entry),
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index bb28cd786..a3155b79d 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -148,7 +148,7 @@ def get_or_try_fetching(entry) do
Logger.debug("Trying to get entry from db")
with id when not is_nil(id) <- string_from_xpath("//activity:object[1]/id", entry),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
{:ok, activity}
else
_ ->
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index e94c5415a..823619edb 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -93,8 +93,7 @@ def object(conn, %{"uuid" => uuid}) do
ActivityPubController.call(conn, :object)
else
with id <- o_status_url(conn, :object, uuid),
- {_, %Activity{} = activity} <-
- {:activity, Activity.get_create_activity_by_object_ap_id(id)},
+ {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id(id)},
{_, true} <- {:public?, ActivityPub.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex
index 82b30950c..bd9d9f3a7 100644
--- a/lib/pleroma/web/push/subscription.ex
+++ b/lib/pleroma/web/push/subscription.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Web.Push.Subscription do
alias Pleroma.Web.Push.Subscription
schema "push_subscriptions" do
- belongs_to(:user, User)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
belongs_to(:token, Token)
field(:endpoint, :string)
field(:key_p256dh, :string)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 68b02d8ca..b83790858 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -107,6 +107,11 @@ defmodule Pleroma.Web.Router do
get("/captcha", UtilController, :captcha)
end
+ scope "/api/pleroma", Pleroma.Web do
+ pipe_through(:pleroma_api)
+ post("/uploader_callback/:upload_path", UploaderController, :callback)
+ end
+
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through(:admin_api)
delete("/user", AdminAPIController, :user_delete)
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 3136b1b9d..978c77e57 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -205,6 +205,15 @@ def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = ite
end)
end
+ def push_to_socket(topics, topic, %Activity{id: id, data: %{"type" => "Delete"}}) do
+ Enum.each(topics[topic] || [], fn socket ->
+ send(
+ socket.transport_pid,
+ {:text, %{event: "delete", payload: to_string(id)} |> Jason.encode!()}
+ )
+ end)
+ end
+
def push_to_socket(topics, topic, item) do
Enum.each(topics[topic] || [], fn socket ->
# Get the current user so we have up-to-date blocks etc.
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 7a63724f1..7d00c01a1 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -70,14 +70,14 @@ def unblock(%User{} = blocker, params) do
def repeat(%User{} = user, ap_id_or_id) do
with {:ok, _announce, %{data: %{"id" => id}}} <- CommonAPI.repeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
{:ok, activity}
end
end
def unrepeat(%User{} = user, ap_id_or_id) do
with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
{:ok, activity}
end
end
@@ -92,14 +92,14 @@ def unpin(%User{} = user, ap_id_or_id) do
def fav(%User{} = user, ap_id_or_id) do
with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
{:ok, activity}
end
end
def unfav(%User{} = user, ap_id_or_id) do
with {:ok, _unfav, _fav, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
{:ok, activity}
end
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 1c728166c..3064d61ea 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -265,8 +265,6 @@ def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- id = String.to_integer(id)
-
with context when is_binary(context) <- TwitterAPI.conversation_id_to_context(id),
activities <-
ActivityPub.fetch_activities_for_context(context, %{
@@ -330,54 +328,57 @@ def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
end
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
+ activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
if activity.data["type"] == "Create" do
activity
else
- Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ Activity.get_create_by_object_ap_id(activity.data["object"])
end
end
def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.fav(user, id) do
+ with {:ok, activity} <- TwitterAPI.fav(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
+ else
+ _ -> json_reply(conn, 400, Jason.encode!(%{}))
end
end
def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.unfav(user, id) do
+ with {:ok, activity} <- TwitterAPI.unfav(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
+ else
+ _ -> json_reply(conn, 400, Jason.encode!(%{}))
end
end
def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.repeat(user, id) do
+ with {:ok, activity} <- TwitterAPI.repeat(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
+ else
+ _ -> json_reply(conn, 400, Jason.encode!(%{}))
end
end
def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.unrepeat(user, id) do
+ with {:ok, activity} <- TwitterAPI.unrepeat(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
+ else
+ _ -> json_reply(conn, 400, Jason.encode!(%{}))
end
end
def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.pin(user, id) do
+ with {:ok, activity} <- TwitterAPI.pin(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
@@ -388,8 +389,7 @@ def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
def unpin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
- {:ok, activity} <- TwitterAPI.unpin(user, id) do
+ with {:ok, activity} <- TwitterAPI.unpin(user, id) do
conn
|> put_view(ActivityView)
|> render("activity.json", %{activity: activity, for: user})
@@ -556,7 +556,6 @@ def friend_requests(conn, params) do
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- uid when is_number(uid) <- String.to_integer(uid),
%User{} = follower <- Repo.get(User, uid),
{:ok, follower} <- User.maybe_follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
@@ -578,7 +577,6 @@ def approve_friend_request(conn, %{"user_id" => uid} = _params) do
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- uid when is_number(uid) <- String.to_integer(uid),
%User{} = follower <- Repo.get(User, uid),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
@@ -675,7 +673,7 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => _query} = params) do
end
def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do
- users = User.search(query, true)
+ users = User.search(query, true, user)
conn
|> put_view(UserView)
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 03708d84c..5eb06a26e 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -168,7 +168,7 @@ def render("activity.json", %{activity: %{data: %{"type" => "Follow"}} = activit
def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activity} = opts) do
user = get_user(activity.data["actor"], opts)
created_at = activity.data["published"] |> Utils.date_to_asctime()
- announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ announced_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
text = "#{user.nickname} retweeted a status."
@@ -192,7 +192,7 @@ def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activ
def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do
user = get_user(activity.data["actor"], opts)
- liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+ liked_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
liked_activity_id = if liked_activity, do: liked_activity.id, else: nil
created_at =
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index a8cf83613..15682db8f 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -108,6 +108,7 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do
"locked" => user.info.locked,
"default_scope" => user.info.default_scope,
"no_rich_text" => user.info.no_rich_text,
+ "hide_network" => user.info.hide_network,
"fields" => fields,
# Pleroma extension
diff --git a/lib/pleroma/web/uploader_controller.ex b/lib/pleroma/web/uploader_controller.ex
new file mode 100644
index 000000000..6c28d1197
--- /dev/null
+++ b/lib/pleroma/web/uploader_controller.ex
@@ -0,0 +1,25 @@
+defmodule Pleroma.Web.UploaderController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Uploaders.Uploader
+
+ def callback(conn, params = %{"upload_path" => upload_path}) do
+ process_callback(conn, :global.whereis_name({Uploader, upload_path}), params)
+ end
+
+ def callbacks(conn, _) do
+ send_resp(conn, 400, "bad request")
+ end
+
+ defp process_callback(conn, pid, params) when is_pid(pid) do
+ send(pid, {Uploader, self(), conn, params})
+
+ receive do
+ {Uploader, conn} -> conn
+ end
+ end
+
+ defp process_callback(conn, _, _) do
+ send_resp(conn, 400, "bad request")
+ end
+end
diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex
index 105b0069f..969ee0684 100644
--- a/lib/pleroma/web/websub/websub_client_subscription.ex
+++ b/lib/pleroma/web/websub/websub_client_subscription.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do
field(:state, :string)
field(:subscribers, {:array, :string}, default: [])
field(:hub, :string)
- belongs_to(:user, User)
+ belongs_to(:user, User, type: Pleroma.FlakeId)
timestamps()
end
diff --git a/priv/repo/migrations/20181218172826_users_and_activities_flake_id.exs b/priv/repo/migrations/20181218172826_users_and_activities_flake_id.exs
new file mode 100644
index 000000000..47d2d02da
--- /dev/null
+++ b/priv/repo/migrations/20181218172826_users_and_activities_flake_id.exs
@@ -0,0 +1,125 @@
+defmodule Pleroma.Repo.Migrations.UsersAndActivitiesFlakeId do
+ use Ecto.Migration
+ alias Pleroma.Clippy
+ require Integer
+ import Ecto.Query
+ alias Pleroma.Repo
+
+ # This migrates from int serial IDs to custom Flake:
+ # 1- create a temporary uuid column
+ # 2- fill this column with compatibility ids (see below)
+ # 3- remove pkeys constraints
+ # 4- update relation pkeys with the new ids
+ # 5- rename the temporary column to id
+ # 6- re-create the constraints
+ def change do
+ # Old serial int ids are transformed to 128bits with extra padding.
+ # The application (in `Pleroma.FlakeId`) handles theses IDs properly as integers; to keep compatibility
+ # with previously issued ids.
+ #execute "update activities set external_id = CAST( LPAD( TO_HEX(id), 32, '0' ) AS uuid);"
+ #execute "update users set external_id = CAST( LPAD( TO_HEX(id), 32, '0' ) AS uuid);"
+
+ clippy = start_clippy_heartbeats()
+
+ # Lock both tables to avoid a running server to meddling with our transaction
+ execute "LOCK TABLE activities;"
+ execute "LOCK TABLE users;"
+
+ execute """
+ ALTER TABLE activities
+ DROP CONSTRAINT activities_pkey CASCADE,
+ ALTER COLUMN id DROP default,
+ ALTER COLUMN id SET DATA TYPE uuid USING CAST( LPAD( TO_HEX(id), 32, '0' ) AS uuid),
+ ADD PRIMARY KEY (id);
+ """
+
+ execute """
+ ALTER TABLE users
+ DROP CONSTRAINT users_pkey CASCADE,
+ ALTER COLUMN id DROP default,
+ ALTER COLUMN id SET DATA TYPE uuid USING CAST( LPAD( TO_HEX(id), 32, '0' ) AS uuid),
+ ADD PRIMARY KEY (id);
+ """
+
+ execute "UPDATE users SET info = jsonb_set(info, '{pinned_activities}', array_to_json(ARRAY(select jsonb_array_elements_text(info->'pinned_activities')))::jsonb);"
+
+ # Fkeys:
+ # Activities - Referenced by:
+ # TABLE "notifications" CONSTRAINT "notifications_activity_id_fkey" FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE
+ # Users - Referenced by:
+ # TABLE "filters" CONSTRAINT "filters_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
+ # TABLE "lists" CONSTRAINT "lists_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
+ # TABLE "notifications" CONSTRAINT "notifications_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
+ # TABLE "oauth_authorizations" CONSTRAINT "oauth_authorizations_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
+ # TABLE "oauth_tokens" CONSTRAINT "oauth_tokens_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
+ # TABLE "password_reset_tokens" CONSTRAINT "password_reset_tokens_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
+ # TABLE "push_subscriptions" CONSTRAINT "push_subscriptions_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
+ # TABLE "websub_client_subscriptions" CONSTRAINT "websub_client_subscriptions_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
+
+ execute """
+ ALTER TABLE notifications
+ ALTER COLUMN activity_id SET DATA TYPE uuid USING CAST( LPAD( TO_HEX(activity_id), 32, '0' ) AS uuid),
+ ADD CONSTRAINT notifications_activity_id_fkey FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE;
+ """
+
+ for table <- ~w(notifications filters lists oauth_authorizations oauth_tokens password_reset_tokens push_subscriptions websub_client_subscriptions) do
+ execute """
+ ALTER TABLE #{table}
+ ALTER COLUMN user_id SET DATA TYPE uuid USING CAST( LPAD( TO_HEX(user_id), 32, '0' ) AS uuid),
+ ADD CONSTRAINT #{table}_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ """
+ end
+
+ flush()
+
+ stop_clippy_heartbeats(clippy)
+ end
+
+ defp start_clippy_heartbeats() do
+ count = from(a in "activities", select: count(a.id)) |> Repo.one!
+
+ if count > 5000 do
+ heartbeat_interval = :timer.minutes(2) + :timer.seconds(30)
+ all_tips = Clippy.tips() ++ [
+ "The migration is still running, maybe it's time for another “tea”?",
+ "Happy rabbits practice a cute behavior known as a\n“binky:” they jump up in the air\nand twist\nand spin around!",
+ "Nothing and everything.\n\nI still work.",
+ "Pleroma runs on a Raspberry Pi!\n\n … but this migration will take forever if you\nactually run on a raspberry pi",
+ "Status? Stati? Post? Note? Toot?\nRepeat? Reboost? Boost? Retweet? Retoot??\n\nI-I'm confused.",
+ ]
+
+ heartbeat = fn(heartbeat, runs, all_tips, tips) ->
+ tips = if Integer.is_even(runs) do
+ tips = if tips == [], do: all_tips, else: tips
+ [tip | tips] = Enum.shuffle(tips)
+ Clippy.puts(tip)
+ tips
+ else
+ IO.puts "\n -- #{DateTime.to_string(DateTime.utc_now())} Migration still running, please wait…\n"
+ tips
+ end
+ :timer.sleep(heartbeat_interval)
+ heartbeat.(heartbeat, runs + 1, all_tips, tips)
+ end
+
+ Clippy.puts [
+ [:red, :bright, "It looks like you are running an older instance!"],
+ [""],
+ [:bright, "This migration may take a long time", :reset, " -- so you probably should"],
+ ["go drink a cofe, or a tea, or a beer, a whiskey, a vodka,"],
+ ["while it runs to deal with your temporary fediverse pause!"]
+ ]
+ :timer.sleep(heartbeat_interval)
+ spawn_link(fn() -> heartbeat.(heartbeat, 1, all_tips, []) end)
+ end
+ end
+
+ defp stop_clippy_heartbeats(pid) do
+ if pid do
+ Process.unlink(pid)
+ Process.exit(pid, :kill)
+ Clippy.puts [[:green, :bright, "Hurray!!", "", "", "Migration completed!"]]
+ end
+ end
+
+end
diff --git a/priv/repo/migrations/20190115085500_create_user_fts_index.exs b/priv/repo/migrations/20190115085500_create_user_fts_index.exs
new file mode 100644
index 000000000..499d67113
--- /dev/null
+++ b/priv/repo/migrations/20190115085500_create_user_fts_index.exs
@@ -0,0 +1,17 @@
+defmodule Pleroma.Repo.Migrations.CreateUserFtsIndex do
+ use Ecto.Migration
+
+ def change do
+ create index(
+ :users,
+ [
+ """
+ (setweight(to_tsvector('simple', regexp_replace(nickname, '\\W', ' ', 'g')), 'A') ||
+ setweight(to_tsvector('simple', regexp_replace(coalesce(name, ''), '\\W', ' ', 'g')), 'B'))
+ """
+ ],
+ name: :users_fts_index,
+ using: :gin
+ )
+ end
+end
diff --git a/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs b/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs
new file mode 100644
index 000000000..b4e8c984c
--- /dev/null
+++ b/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs
@@ -0,0 +1,22 @@
+defmodule Pleroma.Repo.Migrations.FixUserTrigramIndex do
+ use Ecto.Migration
+
+ def up do
+ drop_if_exists(index(:users, [], name: :users_trigram_index))
+
+ create(
+ index(:users, ["(trim(nickname || ' ' || coalesce(name, ''))) gist_trgm_ops"],
+ name: :users_trigram_index,
+ using: :gist
+ )
+ )
+ end
+
+ def down do
+ drop_if_exists(index(:users, [], name: :users_trigram_index))
+
+ create(
+ index(:users, ["(nickname || name) gist_trgm_ops"], name: :users_trigram_index, using: :gist)
+ )
+ end
+end
diff --git a/priv/repo/migrations/20190122153157_update_activity_visibility.exs b/priv/repo/migrations/20190122153157_update_activity_visibility.exs
new file mode 100644
index 000000000..30075137c
--- /dev/null
+++ b/priv/repo/migrations/20190122153157_update_activity_visibility.exs
@@ -0,0 +1,36 @@
+defmodule Pleroma.Repo.Migrations.UpdateActivityVisibility do
+ use Ecto.Migration
+ @disable_ddl_transaction true
+
+ def up do
+ definition = """
+ create or replace function activity_visibility(actor varchar, recipients varchar[], data jsonb) returns varchar as $$
+ DECLARE
+ fa varchar;
+ public varchar := 'https://www.w3.org/ns/activitystreams#Public';
+ BEGIN
+ SELECT COALESCE(users.follower_address, '') into fa from users where users.ap_id = actor;
+
+ IF data->'to' ? public THEN
+ RETURN 'public';
+ ELSIF data->'cc' ? public THEN
+ RETURN 'unlisted';
+ ELSIF ARRAY[fa] && recipients THEN
+ RETURN 'private';
+ ELSIF not(ARRAY[fa, public] && recipients) THEN
+ RETURN 'direct';
+ ELSE
+ RETURN 'unknown';
+ END IF;
+ END;
+ $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE SECURITY DEFINER;
+ """
+
+ execute(definition)
+
+ end
+
+ def down do
+
+ end
+end
diff --git a/priv/repo/migrations/20190123125839_fix_info_ids.exs b/priv/repo/migrations/20190123125839_fix_info_ids.exs
new file mode 100644
index 000000000..2b4c2b5a9
--- /dev/null
+++ b/priv/repo/migrations/20190123125839_fix_info_ids.exs
@@ -0,0 +1,9 @@
+defmodule Pleroma.Repo.Migrations.FixInfoIds do
+ use Ecto.Migration
+
+ def change do
+ execute(
+ "update users set info = jsonb_set(info, '{id}', to_jsonb(uuid_generate_v4())) where info->'id' is null;"
+ )
+ end
+end
diff --git a/priv/repo/migrations/20190124131141_update_activity_visibility_again.exs b/priv/repo/migrations/20190124131141_update_activity_visibility_again.exs
new file mode 100644
index 000000000..0519a5143
--- /dev/null
+++ b/priv/repo/migrations/20190124131141_update_activity_visibility_again.exs
@@ -0,0 +1,37 @@
+defmodule Pleroma.Repo.Migrations.UpdateActivityVisibilityAgain do
+ use Ecto.Migration
+ @disable_ddl_transaction true
+
+ def up do
+ definition = """
+ create or replace function activity_visibility(actor varchar, recipients varchar[], data jsonb) returns varchar as $$
+ DECLARE
+ fa varchar;
+ public varchar := 'https://www.w3.org/ns/activitystreams#Public';
+ BEGIN
+ SELECT COALESCE(users.follower_address, '') into fa from public.users where users.ap_id = actor;
+
+ IF data->'to' ? public THEN
+ RETURN 'public';
+ ELSIF data->'cc' ? public THEN
+ RETURN 'unlisted';
+ ELSIF ARRAY[fa] && recipients THEN
+ RETURN 'private';
+ ELSIF not(ARRAY[fa, public] && recipients) THEN
+ RETURN 'direct';
+ ELSE
+ RETURN 'unknown';
+ END IF;
+ END;
+ $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE SECURITY DEFINER;
+ """
+
+ execute(definition)
+
+ end
+
+ def down do
+
+ end
+
+end
diff --git a/priv/static/index.html b/priv/static/index.html
index 83c11118c..aa6c1412e 100644
--- a/priv/static/index.html
+++ b/priv/static/index.html
@@ -1 +1 @@
-Pleroma
\ No newline at end of file
+Pleroma
\ No newline at end of file
diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld
index 819d25c38..15645646a 100644
--- a/priv/static/schemas/litepub-0.1.jsonld
+++ b/priv/static/schemas/litepub-0.1.jsonld
@@ -17,7 +17,9 @@
"toot": "http://joinmastodon.org/ns#",
"totalItems": "as:totalItems",
"value": "schema:value",
- "sensitive": "as:sensitive"
+ "sensitive": "as:sensitive",
+ "litepub": "http://litepub.social/ns#",
+ "directMessage": "litepub:directMessage"
}
]
}
diff --git a/priv/static/static/config.json b/priv/static/static/config.json
index cc72900a8..24e26696f 100644
--- a/priv/static/static/config.json
+++ b/priv/static/static/config.json
@@ -18,5 +18,6 @@
"hideUserStats": false,
"loginMethod": "password",
"webPushNotifications": false,
- "noAttachmentLinks": false
+ "noAttachmentLinks": false,
+ "nsfwCensorImage": ""
}
diff --git a/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css b/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css
new file mode 100644
index 000000000..d52d4489d
Binary files /dev/null and b/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css differ
diff --git a/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css.map b/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css.map
new file mode 100644
index 000000000..c1db7d9d5
--- /dev/null
+++ b/priv/static/static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack:///src/components/timeline/timeline.vue","webpack:///webpack:///src/components/status/status.vue","webpack:///webpack:///src/components/attachment/attachment.vue","webpack:///webpack:///src/components/still-image/still-image.vue","webpack:///webpack:///src/components/favorite_button/favorite_button.vue","webpack:///webpack:///src/components/retweet_button/retweet_button.vue","webpack:///webpack:///src/components/delete_button/delete_button.vue","webpack:///webpack:///src/components/post_status_form/post_status_form.vue","webpack:///webpack:///src/components/media_upload/media_upload.vue","webpack:///webpack:///src/components/user_card_content/user_card_content.vue","webpack:///webpack:///src/components/status_or_conversation/status_or_conversation.vue","webpack:///webpack:///src/components/user_card/user_card.vue","webpack:///webpack:///src/components/user_profile/user_profile.vue","webpack:///webpack:///src/components/settings/settings.vue","webpack:///webpack:///src/components/tab_switcher/src/components/tab_switcher/tab_switcher.scss","webpack:///webpack:///src/components/style_switcher/style_switcher.scss","webpack:///webpack:///src/components/color_input/color_input.vue","webpack:///webpack:///src/components/shadow_control/shadow_control.vue","webpack:///webpack:///src/components/font_control/font_control.vue","webpack:///webpack:///src/components/contrast_ratio/contrast_ratio.vue","webpack:///webpack:///src/components/export_import/export_import.vue","webpack:///webpack:///src/components/registration/registration.vue","webpack:///webpack:///src/components/user_settings/user_settings.vue","webpack:///webpack:///src/components/user_search/user_search.vue","webpack:///webpack:///src/components/notifications/notifications.scss","webpack:///webpack:///src/components/user_panel/user_panel.vue","webpack:///webpack:///src/components/login_form/login_form.vue","webpack:///webpack:///src/components/chat_panel/chat_panel.vue","webpack:///webpack:///src/components/features_panel/features_panel.vue","webpack:///webpack:///src/components/terms_of_service_panel/terms_of_service_panel.vue","webpack:///webpack:///src/App.scss","webpack:///webpack:///src/components/nav_panel/nav_panel.vue","webpack:///webpack:///src/components/user_finder/user_finder.vue","webpack:///webpack:///src/components/who_to_follow_panel/who_to_follow_panel.vue","webpack:///webpack:///src/components/side_drawer/side_drawer.vue"],"names":[],"mappings":"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","file":"static/css/app.3d3e30a9afb8c41739656f496e8c79e6.css","sourcesContent":["\n.timeline .loadmore-text{opacity:1\n}\n.new-status-notification{position:relative;margin-top:-1px;font-size:1.1em;border-width:1px 0 0 0;border-style:solid;border-color:var(--border, #222);padding:10px;z-index:1;background-color:#182230;background-color:var(--panel, #182230)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/timeline/timeline.vue","\n.status-body{-ms-flex:1;flex:1;min-width:0\n}\n.status-preview.status-el{border-style:solid;border-width:1px;border-color:#222;border-color:var(--border, #222)\n}\n.status-preview-container{position:relative;max-width:100%\n}\n.status-preview{position:absolute;max-width:95%;display:-ms-flexbox;display:flex;background-color:#121a24;background-color:var(--bg, #121a24);border-color:#222;border-color:var(--border, #222);border-style:solid;border-width:1px;border-radius:5px;border-radius:var(--tooltipRadius, 5px);box-shadow:2px 2px 3px rgba(0,0,0,0.5);box-shadow:var(--popupShadow);margin-top:0.25em;margin-left:0.5em;z-index:50\n}\n.status-preview .status{-ms-flex:1;flex:1;border:0;min-width:15em\n}\n.status-preview-loading{display:block;min-width:15em;padding:1em;text-align:center;border-width:1px;border-style:solid\n}\n.status-preview-loading i{font-size:2em\n}\n.status-el{-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;border-left-width:0px;line-height:18px;min-width:0;border-color:#222;border-color:var(--border, #222);border-left:4px red;border-left:4px var(--cRed, red)\n}\n.status-el_focused{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.timeline .status-el{border-bottom-width:1px;border-bottom-style:solid\n}\n.status-el .media-body{-ms-flex:1;flex:1;padding:0;margin:0 0 0.25em 0.8em\n}\n.status-el .usercard{margin-bottom:.7em\n}\n.status-el .media-heading{-ms-flex-wrap:nowrap;flex-wrap:nowrap;line-height:18px\n}\n.status-el .media-heading-left{padding:0;vertical-align:bottom;-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.status-el .media-heading-left small{font-weight:lighter\n}\n.status-el .media-heading-left h4{white-space:nowrap;font-size:14px;margin-right:0.25em;overflow:hidden;text-overflow:ellipsis\n}\n.status-el .media-heading-left .name-and-links{padding:0;-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:baseline;align-items:baseline\n}\n.status-el .media-heading-left .name-and-links .user-name{margin-right:.45em\n}\n.status-el .media-heading-left .name-and-links .user-name img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.status-el .media-heading-left .links{display:-ms-flexbox;display:flex;font-size:12px;color:#d8a070;color:var(--link, #d8a070);max-width:100%\n}\n.status-el .media-heading-left .links a{max-width:100%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap\n}\n.status-el .media-heading-left .reply-info{display:-ms-flexbox;display:flex\n}\n.status-el .media-heading-left .replies{line-height:16px\n}\n.status-el .media-heading-left .reply-link{margin-right:0.2em\n}\n.status-el .media-heading-right{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-negative:0;flex-shrink:0;-ms-flex-wrap:nowrap;flex-wrap:nowrap;margin-left:.25em;-ms-flex-item-align:baseline;align-self:baseline\n}\n.status-el .media-heading-right .timeago{margin-right:0.2em;font-size:12px;-ms-flex-item-align:last baseline;-ms-grid-row-align:last baseline;align-self:last baseline\n}\n.status-el .media-heading-right>*{margin-left:0.2em\n}\n.status-el .media-heading-right a:hover i{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.status-el a{display:inline-block;word-break:break-all\n}\n.status-el .tall-status{position:relative;height:220px;overflow-x:hidden;overflow-y:hidden\n}\n.status-el .tall-status-hider{position:absolute;height:70px;margin-top:150px;width:100%;text-align:center;line-height:110px;background:linear-gradient(to bottom, transparent, #121a24 80%);background:linear-gradient(to bottom, transparent, var(--bg, #121a24) 80%)\n}\n.status-el .tall-status-hider_focused{background:linear-gradient(to bottom, transparent, #151e2a 80%);background:linear-gradient(to bottom, transparent, var(--lightBg, #151e2a) 80%)\n}\n.status-el .status-unhider,.status-el .cw-status-hider{width:100%;text-align:center\n}\n.status-el .status-content{margin-right:0.5em;font-family:var(--postFont, sans-serif)\n}\n.status-el .status-content img,.status-el .status-content video{max-width:100%;max-height:400px;vertical-align:middle;object-fit:contain\n}\n.status-el .status-content blockquote{margin:0.2em 0 0.2em 2em;font-style:italic\n}\n.status-el .status-content pre{overflow:auto\n}\n.status-el .status-content code,.status-el .status-content samp,.status-el .status-content kbd,.status-el .status-content var,.status-el .status-content pre{font-family:var(--postCodeFont, monospace)\n}\n.status-el .status-content p{margin:0;margin-top:0.2em;margin-bottom:0.5em\n}\n.status-el .status-content h1{font-size:1.1em;line-height:1.2em;margin:1.4em 0\n}\n.status-el .status-content h2{font-size:1.1em;margin:1.0em 0\n}\n.status-el .status-content h3{font-size:1em;margin:1.2em 0\n}\n.status-el .status-content h4{margin:1.1em 0\n}\n.status-el .retweet-info{padding:0.4em 0.6em 0 0.6em;margin:0\n}\n.status-el .retweet-info .avatar{border-radius:10px;border-radius:var(--avatarAltRadius, 10px);margin-left:28px;width:20px;height:20px\n}\n.status-el .retweet-info .media-body{font-size:1em;line-height:22px;display:-ms-flexbox;display:flex;-ms-flex-line-pack:center;align-content:center;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.status-el .retweet-info .media-body .user-name{font-weight:bold\n}\n.status-el .retweet-info .media-body .user-name img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.status-el .retweet-info .media-body i{padding:0 0.2em\n}\n.status-el .retweet-info .media-body a{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\n}\n.status-fadein{animation-duration:0.4s;animation-name:fadein\n}\n@keyframes fadein{\nfrom{opacity:0\n}\nto{opacity:1\n}\n}\n.greentext{color:green\n}\n.status-conversation{border-left-style:solid\n}\n.status-actions{width:100%;display:-ms-flexbox;display:flex\n}\n.status-actions div,.status-actions favorite-button{padding-top:0.25em;max-width:6em;-ms-flex:1;flex:1\n}\n.icon-reply:hover{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.icon-reply.icon-reply-active{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.status .avatar-compact{width:32px;height:32px;box-shadow:var(--avatarStatusShadow);border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.status .avatar-compact.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.avatar.still-image{width:48px;height:48px;box-shadow:var(--avatarStatusShadow);border-radius:4px;border-radius:var(--avatarRadius, 4px);overflow:hidden;position:relative\n}\n.avatar.still-image.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.avatar.still-image img{width:100%;height:100%\n}\n.avatar.still-image.animated::before{display:none\n}\n.status:hover .animated.avatar canvas{display:none\n}\n.status:hover .animated.avatar img{visibility:visible\n}\n.status{display:-ms-flexbox;display:flex;padding:0.6em\n}\n.status.is-retweet{padding-top:0.1em\n}\n.status-conversation:last-child{border-bottom:none\n}\n.muted{padding:0.25em 0.5em\n}\n.muted button{margin-left:auto\n}\n.muted .muteWords{margin-left:10px\n}\na.unmute{display:block;margin-left:auto\n}\n.reply-left{-ms-flex:0;flex:0;min-width:48px\n}\n.reply-body{-ms-flex:1;flex:1\n}\n.timeline>.status-el:last-child{border-bottom-radius:0 0 10px 10px;border-radius:0 0 var(--panelRadius, 10px) var(--panelRadius, 10px);border-bottom:none\n}\n@media all and (max-width: 960px){\n.status-el .retweet-info .avatar{margin-left:20px\n}\n.status{max-width:100%\n}\n.status .avatar{width:40px;height:40px\n}\n.status .avatar-compact{width:32px;height:32px\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/status/status.vue","\n.attachments{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.attachments .attachment.media-upload-container{-ms-flex:0 0 auto;flex:0 0 auto;max-height:300px;max-width:100%\n}\n.attachments .placeholder{margin-right:0.5em\n}\n.attachments .nsfw-placeholder{cursor:pointer\n}\n.attachments .nsfw-placeholder.loading{cursor:progress\n}\n.attachments .small-attachment{max-height:100px\n}\n.attachments .small-attachment.image,.attachments .small-attachment.video{max-width:35%\n}\n.attachments .attachment{position:relative;-ms-flex:1 0 30%;flex:1 0 30%;margin:0.5em 0.7em 0.6em 0.0em;-ms-flex-item-align:start;align-self:flex-start;line-height:0;border-style:solid;border-width:1px;border-radius:10px;border-radius:var(--attachmentRadius, 10px);border-color:#222;border-color:var(--border, #222);overflow:hidden\n}\n.attachments .fullwidth{-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.attachments.video{line-height:0\n}\n.attachments.html{-ms-flex-preferred-size:90%;flex-basis:90%;width:100%;display:-ms-flexbox;display:flex\n}\n.attachments .hider{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);font-weight:bold;z-index:4;line-height:1;border-radius:5px;border-radius:var(--tooltipRadius, 5px)\n}\n.attachments .small{max-height:100px\n}\n.attachments video{max-height:500px;height:100%;width:100%;z-index:0\n}\n.attachments audio{width:100%\n}\n.attachments img.media-upload{line-height:0;max-height:300px;max-width:100%\n}\n.attachments .oembed{line-height:1.2em;-ms-flex:1 0 100%;flex:1 0 100%;width:100%;margin-right:15px;display:-ms-flexbox;display:flex\n}\n.attachments .oembed img{width:100%\n}\n.attachments .oembed .image{-ms-flex:1;flex:1\n}\n.attachments .oembed .image img{border:0px;border-radius:5px;height:100%;object-fit:cover\n}\n.attachments .oembed .text{-ms-flex:2;flex:2;margin:8px;word-break:break-all\n}\n.attachments .oembed .text h1{font-size:14px;margin:0px\n}\n.attachments .image-attachment{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1\n}\n.attachments .image-attachment.hidden{display:none\n}\n.attachments .image-attachment .still-image{width:100%;height:100%\n}\n.attachments .image-attachment .small img{max-height:100px\n}\n.attachments .image-attachment img{object-fit:contain;width:100%;height:100%;max-height:500px;image-orientation:from-image\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/attachment/attachment.vue","\n.still-image{position:relative;line-height:0;overflow:hidden;width:100%;height:100%\n}\n.still-image:hover canvas{display:none\n}\n.still-image img{width:100%;height:100%;object-fit:contain\n}\n.still-image.animated:hover::before,.still-image.animated img{visibility:hidden\n}\n.still-image.animated:hover img{visibility:visible\n}\n.still-image.animated::before{content:'gif';position:absolute;line-height:10px;font-size:10px;top:5px;left:5px;background:rgba(127,127,127,0.5);color:#FFF;display:block;padding:2px 4px;border-radius:5px;border-radius:var(--tooltipRadius, 5px);z-index:2\n}\n.still-image canvas{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;object-fit:contain\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/still-image/still-image.vue","\n.fav-active{cursor:pointer;animation-duration:0.6s\n}\n.fav-active:hover{color:orange;color:var(--cOrange, orange)\n}\n.favorite-button.icon-star{color:orange;color:var(--cOrange, orange)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/favorite_button/favorite_button.vue","\n.rt-active{cursor:pointer;animation-duration:0.6s\n}\n.rt-active:hover{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n.icon-retweet.retweeted{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/retweet_button/retweet_button.vue","\n.icon-cancel,.delete-status{cursor:pointer\n}\n.icon-cancel:hover,.delete-status:hover{color:red;color:var(--cRed, red)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/delete_button/delete_button.vue","\n.tribute-container ul{padding:0px\n}\n.tribute-container ul li{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center\n}\n.tribute-container img{padding:3px;width:16px;height:16px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.post-status-form .form-bottom,.login .form-bottom{display:-ms-flexbox;display:flex;padding:0.5em;height:32px\n}\n.post-status-form .form-bottom button,.login .form-bottom button{width:10em\n}\n.post-status-form .form-bottom p,.login .form-bottom p{margin:0.35em;padding:0.35em;display:-ms-flexbox;display:flex\n}\n.post-status-form .error,.login .error{text-align:center\n}\n.post-status-form .media-upload-wrapper,.login .media-upload-wrapper{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;min-width:50px;margin-right:.2em;margin-bottom:.5em\n}\n.post-status-form .media-upload-wrapper .icon-cancel,.login .media-upload-wrapper .icon-cancel{display:inline-block;position:static;margin:0;padding-bottom:0;margin-left:10px;margin-left:var(--attachmentRadius, 10px);background-color:#182230;background-color:var(--btn, #182230);border-bottom-left-radius:0;border-bottom-right-radius:0\n}\n.post-status-form .attachments,.login .attachments{padding:0 0.5em\n}\n.post-status-form .attachments .attachment,.login .attachments .attachment{margin:0;position:relative;-ms-flex:0 0 auto;flex:0 0 auto;border:1px solid #222;border:1px solid var(--border, #222);text-align:center\n}\n.post-status-form .attachments .attachment audio,.login .attachments .attachment audio{min-width:300px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.post-status-form .attachments .attachment a,.login .attachments .attachment a{display:block;text-align:left;line-height:1.2;padding:.5em\n}\n.post-status-form .attachments i,.login .attachments i{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);border-radius:10px;border-radius:var(--attachmentRadius, 10px);font-weight:bold\n}\n.post-status-form .btn,.login .btn{cursor:pointer\n}\n.post-status-form .btn[disabled],.login .btn[disabled]{cursor:not-allowed\n}\n.post-status-form form,.login form{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.6em\n}\n.post-status-form .form-group,.login .form-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.3em 0.5em 0.6em;line-height:24px\n}\n.post-status-form form textarea.form-cw,.login form textarea.form-cw{line-height:16px;resize:none;overflow:hidden;transition:min-height 200ms 100ms;min-height:1px\n}\n.post-status-form form textarea.form-control,.login form textarea.form-control{line-height:16px;resize:none;overflow:hidden;transition:min-height 200ms 100ms;min-height:1px;box-sizing:content-box\n}\n.post-status-form form textarea.form-control:focus,.login form textarea.form-control:focus{min-height:48px\n}\n.post-status-form .btn,.login .btn{cursor:pointer\n}\n.post-status-form .btn[disabled],.login .btn[disabled]{cursor:not-allowed\n}\n.post-status-form .icon-cancel,.login .icon-cancel{cursor:pointer;z-index:4\n}\n.post-status-form .autocomplete-panel,.login .autocomplete-panel{margin:0 0.5em 0 0.5em;border-radius:5px;border-radius:var(--tooltipRadius, 5px);position:absolute;z-index:1;box-shadow:1px 2px 4px rgba(0,0,0,0.5);box-shadow:var(--popupShadow);min-width:75%;background:#121a24;background:var(--bg, #121a24);color:#b9b9ba;color:var(--lightText, #b9b9ba)\n}\n.post-status-form .autocomplete,.login .autocomplete{cursor:pointer;padding:0.2em 0.4em 0.2em 0.4em;border-bottom:1px solid rgba(0,0,0,0.4);display:-ms-flexbox;display:flex\n}\n.post-status-form .autocomplete img,.login .autocomplete img{width:24px;height:24px;border-radius:4px;border-radius:var(--avatarRadius, 4px);object-fit:contain\n}\n.post-status-form .autocomplete span,.login .autocomplete span{line-height:24px;margin:0 0.1em 0 0.2em\n}\n.post-status-form .autocomplete small,.login .autocomplete small{margin-left:.5em;color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n.post-status-form .autocomplete.highlighted,.login .autocomplete.highlighted{background-color:#182230;background-color:var(--lightBg, #182230)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/post_status_form/post_status_form.vue","\n.media-upload {\n font-size: 26px;\n -ms-flex: 1;\n flex: 1;\n}\n.icon-upload {\n cursor: pointer;\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/media_upload/media_upload.vue","\n.profile-panel-background{background-size:cover;border-radius:10px;border-radius:var(--panelRadius, 10px);overflow:hidden;border-bottom-left-radius:0;border-bottom-right-radius:0\n}\n.profile-panel-background .panel-heading{padding:.5em 0;text-align:center;box-shadow:none\n}\n.profile-panel-body{word-wrap:break-word;background:linear-gradient(to bottom, transparent, #121a24 80%);background:linear-gradient(to bottom, transparent, var(--bg, #121a24) 80%)\n}\n.profile-panel-body .profile-bio{text-align:center\n}\n.user-info{color:#b9b9ba;color:var(--lightText, #b9b9ba);padding:0 26px\n}\n.user-info .container{padding:16px 0 6px;display:-ms-flexbox;display:flex;max-height:56px\n}\n.user-info .container .avatar{border-radius:4px;border-radius:var(--avatarRadius, 4px);-ms-flex:1 0 100%;flex:1 0 100%;width:56px;height:56px;box-shadow:0px 1px 8px rgba(0,0,0,0.75);box-shadow:var(--avatarShadow);object-fit:cover\n}\n.user-info .container .avatar.better-shadow{box-shadow:var(--avatarShadowInset);filter:var(--avatarShadowFilter)\n}\n.user-info .container .avatar.animated::before{display:none\n}\n.user-info:hover .animated.avatar canvas{display:none\n}\n.user-info:hover .animated.avatar img{visibility:visible\n}\n.user-info .usersettings{color:#b9b9ba;color:var(--lightText, #b9b9ba);opacity:.8\n}\n.user-info .name-and-screen-name{display:block;margin-left:0.6em;text-align:left;text-overflow:ellipsis;white-space:nowrap;-ms-flex:1 1 0px;flex:1 1 0;z-index:1\n}\n.user-info .name-and-screen-name img{width:26px;height:26px;vertical-align:middle;object-fit:contain\n}\n.user-info .name-and-screen-name .top-line{display:-ms-flexbox;display:flex\n}\n.user-info .user-name{text-overflow:ellipsis;overflow:hidden;-ms-flex:1 1 auto;flex:1 1 auto;margin-right:1em\n}\n.user-info .user-screen-name{color:#b9b9ba;color:var(--lightText, #b9b9ba);display:inline-block;font-weight:light;font-size:15px;padding-right:0.1em;width:100%;display:-ms-flexbox;display:flex\n}\n.user-info .user-screen-name .dailyAvg{min-width:1px;-ms-flex:0 0 auto;flex:0 0 auto;margin-left:1em;font-size:0.7em;color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.user-info .user-screen-name .handle{min-width:1px;-ms-flex:0 1 auto;flex:0 1 auto;text-overflow:ellipsis;overflow:hidden\n}\n.user-info .user-meta{margin-bottom:.15em;display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;font-size:14px;line-height:22px;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.user-info .user-meta .following{-ms-flex:1 0 auto;flex:1 0 auto;margin:0;margin-bottom:.25em;text-align:left\n}\n.user-info .user-meta .highlighter{-ms-flex:0 1 auto;flex:0 1 auto;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-.5em;-ms-flex-item-align:start;align-self:start\n}\n.user-info .user-meta .highlighter .userHighlightCl{padding:2px 10px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightSel,.user-info .user-meta .highlighter .userHighlightSel.select{padding-top:0;padding-bottom:0;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightSel.select i{line-height:22px\n}\n.user-info .user-meta .highlighter .userHighlightText{width:70px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightCl,.user-info .user-meta .highlighter .userHighlightText,.user-info .user-meta .highlighter .userHighlightSel,.user-info .user-meta .highlighter .userHighlightSel.select{height:22px;vertical-align:top;margin-right:.5em;margin-bottom:.25em\n}\n.user-info .user-interactions{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-pack:justify;justify-content:space-between;margin-right:-.75em\n}\n.user-info .user-interactions div{-ms-flex:1 0 0px;flex:1 0 0;margin-right:.75em;margin-bottom:.6em;white-space:nowrap\n}\n.user-info .user-interactions .mute{max-width:220px;min-height:28px\n}\n.user-info .user-interactions .remote-follow{max-width:220px;min-height:28px\n}\n.user-info .user-interactions .follow{max-width:220px;min-height:28px\n}\n.user-info .user-interactions button{width:100%;height:100%;margin:0\n}\n.user-info .user-interactions .remote-button{height:28px !important;width:92%\n}\n.user-info .user-interactions .pressed{border-bottom-color:rgba(255,255,255,0.2);border-top-color:rgba(0,0,0,0.2)\n}\n.user-counts{display:-ms-flexbox;display:flex;line-height:16px;padding:.5em 1.5em 0em 1.5em;text-align:center;-ms-flex-pack:justify;justify-content:space-between;color:#b9b9ba;color:var(--lightText, #b9b9ba);-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.user-count{-ms-flex:1 0 auto;flex:1 0 auto;padding:.5em 0 .5em 0;margin:0 .5em\n}\n.user-count h5{font-size:1em;font-weight:bolder;margin:0 0 0.25em\n}\n.user-count a{text-decoration:none\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card_content/user_card_content.vue","\n.spacer{height:1em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/status_or_conversation/status_or_conversation.vue","\n.name-and-screen-name{margin-left:0.7em;margin-top:0.0em;text-align:left;width:100%\n}\n.name-and-screen-name .user-name img{object-fit:contain;height:16px;width:16px;vertical-align:middle\n}\n.follows-you{margin-left:2em;float:right\n}\n.card{display:-ms-flexbox;display:flex;-ms-flex:1 0;flex:1 0;padding-top:0.6em;padding-right:1em;padding-bottom:0.6em;padding-left:1em;border-bottom:1px solid;margin:0;border-bottom-color:#222;border-bottom-color:var(--border, #222)\n}\n.card .avatar{margin-top:0.2em;width:32px;height:32px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.usercard{width:-webkit-fill-available;width:-moz-available;width:fill-available;margin:0.2em 0 0.7em 0;border-radius:10px;border-radius:var(--panelRadius, 10px);border-style:solid;border-color:#222;border-color:var(--border, #222);border-width:1px;overflow:hidden\n}\n.usercard .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.usercard p{margin-bottom:0\n}\n.approval button{width:100%;margin-bottom:0.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card/user_card.vue","\n.user-profile{-ms-flex:2;flex:2;-ms-flex-preferred-size:500px;flex-basis:500px\n}\n.user-profile .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.user-profile .userlist-placeholder{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:middle;align-items:middle;padding:2em\n}\n.user-profile .timeline-heading{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center\n}\n.user-profile .timeline-heading .loadmore-button,.user-profile .timeline-heading .alert{-ms-flex:1;flex:1\n}\n.user-profile .timeline-heading .loadmore-button{height:28px;margin:10px .6em\n}\n.user-profile .timeline-heading .title,.user-profile .timeline-heading .loadmore-text{display:none\n}\n.user-profile-placeholder .panel-body{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:middle;align-items:middle;padding:7em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_profile/user_profile.vue","\n.setting-item{border-bottom:2px solid var(--fg, #182230);margin:1em 1em 1.4em;padding-bottom:1.4em\n}\n.setting-item>div{margin-bottom:.5em\n}\n.setting-item>div:last-child{margin-bottom:0\n}\n.setting-item:last-child{border-bottom:none;padding-bottom:0;margin-bottom:1em\n}\n.setting-item select{min-width:10em\n}\n.setting-item textarea{width:100%;height:100px\n}\n.setting-item .unavailable,.setting-item .unavailable i{color:var(--cRed, red);color:red\n}\n.setting-item .old-avatar{width:128px;border-radius:4px;border-radius:var(--avatarRadius, 4px)\n}\n.setting-item .new-avatar{object-fit:cover;width:128px;height:128px;border-radius:4px;border-radius:var(--avatarRadius, 4px)\n}\n.setting-item .btn{min-height:28px;min-width:10em;padding:0 2em\n}\n.select-multiple{display:-ms-flexbox;display:flex\n}\n.select-multiple .option-list{margin:0;padding-left:.5em\n}\n.setting-list,.option-list{list-style-type:none;padding-left:2em\n}\n.setting-list li,.option-list li{margin-bottom:0.5em\n}\n.setting-list .suboptions,.option-list .suboptions{margin-top:0.3em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/settings/settings.vue","@import '../../_variables.scss';\n\n.tab-switcher {\n .contents {\n .hidden {\n display: none;\n }\n }\n .tabs {\n display: flex;\n position: relative;\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n box-sizing: border-box;\n\n &::after, &::before {\n display: block;\n content: '';\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: $fallback--border;\n border-bottom-color: var(--border, $fallback--border);\n }\n\n .tab-wrapper {\n height: 28px;\n position: relative;\n display: flex;\n flex: 0 0 auto;\n\n .tab {\n width: 100%;\n min-width: 1px;\n position: relative;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding: 6px 1em;\n padding-bottom: 99px;\n margin-bottom: 6px - 99px;\n white-space: nowrap;\n\n &:not(.active) {\n z-index: 4;\n\n &:hover {\n z-index: 6;\n }\n }\n\n &.active {\n background: transparent;\n z-index: 5;\n }\n }\n\n &:not(.active) {\n &::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 7;\n border-bottom: 1px solid;\n border-bottom-color: $fallback--border;\n border-bottom-color: var(--border, $fallback--border);\n }\n }\n }\n\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/tab_switcher/src/components/tab_switcher/tab_switcher.scss","\n.style-switcher .preset-switcher{margin-right:1em\n}\n.style-switcher .style-control{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;margin-bottom:5px\n}\n.style-switcher .style-control .label{-ms-flex:1;flex:1\n}\n.style-switcher .style-control.disabled input:not(.exclude-disabled),.style-switcher .style-control.disabled select:not(.exclude-disabled){opacity:.5\n}\n.style-switcher .style-control input,.style-switcher .style-control select{min-width:3em;margin:0;-ms-flex:0;flex:0\n}\n.style-switcher .style-control input[type=color],.style-switcher .style-control select[type=color]{padding:1px;cursor:pointer;height:29px;min-width:2em;border:none;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.style-switcher .style-control input[type=number],.style-switcher .style-control select[type=number]{min-width:5em\n}\n.style-switcher .style-control input[type=range],.style-switcher .style-control select[type=range]{-ms-flex:1;flex:1;min-width:3em\n}\n.style-switcher .style-control input[type=checkbox]+label,.style-switcher .style-control select[type=checkbox]+label{margin:6px 0\n}\n.style-switcher .style-control input:not([type=number]):not([type=text]),.style-switcher .style-control select:not([type=number]):not([type=text]){-ms-flex-item-align:start;align-self:flex-start\n}\n.style-switcher .tab-switcher{margin:0 -1em\n}\n.style-switcher .reset-container{-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.style-switcher .fonts-container,.style-switcher .reset-container,.style-switcher .apply-container,.style-switcher .radius-container,.style-switcher .color-container{display:-ms-flexbox;display:flex\n}\n.style-switcher .fonts-container,.style-switcher .radius-container{-ms-flex-direction:column;flex-direction:column\n}\n.style-switcher .color-container{-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:justify;justify-content:space-between\n}\n.style-switcher .color-container>h4{width:99%\n}\n.style-switcher .fonts-container,.style-switcher .color-container,.style-switcher .shadow-container,.style-switcher .radius-container,.style-switcher .presets-container{margin:1em 1em 0\n}\n.style-switcher .tab-header{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:baseline;align-items:baseline;width:100%;min-height:30px;margin-bottom:1em\n}\n.style-switcher .tab-header .btn{min-width:1px;-ms-flex:0 auto;flex:0 auto;padding:0 1em\n}\n.style-switcher .tab-header p{-ms-flex:1;flex:1;margin:0;margin-right:.5em\n}\n.style-switcher .shadow-selector .override{-ms-flex:1;flex:1;margin-left:.5em\n}\n.style-switcher .shadow-selector .select-container{margin-top:-4px;margin-bottom:-3px\n}\n.style-switcher .save-load,.style-switcher .save-load-options{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:baseline;align-items:baseline;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.style-switcher .save-load .presets,.style-switcher .save-load .import-export,.style-switcher .save-load-options .presets,.style-switcher .save-load-options .import-export{margin-bottom:.5em\n}\n.style-switcher .save-load .import-export,.style-switcher .save-load-options .import-export{display:-ms-flexbox;display:flex\n}\n.style-switcher .save-load .override,.style-switcher .save-load-options .override{margin-left:.5em\n}\n.style-switcher .save-load-options{-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:.5em;-ms-flex-pack:center;justify-content:center\n}\n.style-switcher .save-load-options .keep-option{margin:0 .5em .5em;min-width:25%\n}\n.style-switcher .preview-container{border-top:1px dashed;border-bottom:1px dashed;border-color:#222;border-color:var(--border, #222);margin:1em -1em 0;padding:1em;background:var(--body-background-image);background-size:cover;background-position:50% 50%\n}\n.style-switcher .preview-container .dummy .post{font-family:var(--postFont);display:-ms-flexbox;display:flex\n}\n.style-switcher .preview-container .dummy .post .content{-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .post .content h4{margin-bottom:.25em\n}\n.style-switcher .preview-container .dummy .post .content .icons{margin-top:.5em;display:-ms-flexbox;display:flex\n}\n.style-switcher .preview-container .dummy .post .content .icons i{margin-right:1em\n}\n.style-switcher .preview-container .dummy .after-post{margin-top:1em;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center\n}\n.style-switcher .preview-container .dummy .avatar,.style-switcher .preview-container .dummy .avatar-alt{background:linear-gradient(135deg, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%);color:black;font-family:sans-serif;text-align:center;margin-right:1em\n}\n.style-switcher .preview-container .dummy .avatar-alt{-ms-flex:0 auto;flex:0 auto;margin-left:28px;font-size:12px;min-width:20px;min-height:20px;line-height:20px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.style-switcher .preview-container .dummy .avatar{-ms-flex:0 auto;flex:0 auto;width:48px;height:48px;font-size:14px;line-height:48px\n}\n.style-switcher .preview-container .dummy .actions{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline\n}\n.style-switcher .preview-container .dummy .actions .checkbox{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:baseline;align-items:baseline;margin-right:1em;-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .separator{margin:1em;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222)\n}\n.style-switcher .preview-container .dummy .panel-heading .badge,.style-switcher .preview-container .dummy .panel-heading .alert,.style-switcher .preview-container .dummy .panel-heading .btn,.style-switcher .preview-container .dummy .panel-heading .faint{margin-left:1em;white-space:nowrap\n}\n.style-switcher .preview-container .dummy .panel-heading .faint{text-overflow:ellipsis;min-width:2em;overflow-x:hidden\n}\n.style-switcher .preview-container .dummy .panel-heading .flex-spacer{-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .btn{margin-left:0;padding:0 1em;min-width:3em;min-height:30px\n}\n.style-switcher .apply-container{-ms-flex-pack:center;justify-content:center\n}\n.style-switcher .radius-item,.style-switcher .color-item{min-width:20em;margin:5px 6px 0 0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex:1 1 0px;flex:1 1 0\n}\n.style-switcher .radius-item.wide,.style-switcher .color-item.wide{min-width:60%\n}\n.style-switcher .radius-item:not(.wide):nth-child(2n+1),.style-switcher .color-item:not(.wide):nth-child(2n+1){margin-right:7px\n}\n.style-switcher .radius-item .color,.style-switcher .radius-item .opacity,.style-switcher .color-item .color,.style-switcher .color-item .opacity{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline\n}\n.style-switcher .radius-item{-ms-flex-preferred-size:auto;flex-basis:auto\n}\n.style-switcher .theme-radius-rn,.style-switcher .theme-color-cl{border:0;box-shadow:none;background:transparent;color:var(--faint, rgba(185,185,186,0.5));-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.style-switcher .theme-color-cl,.style-switcher .theme-radius-in,.style-switcher .theme-color-in{margin-left:4px\n}\n.style-switcher .theme-radius-in{min-width:1em\n}\n.style-switcher .theme-radius-in{max-width:7em;-ms-flex:1;flex:1\n}\n.style-switcher .theme-radius-lb{max-width:50em\n}\n.style-switcher .theme-preview-content{padding:20px\n}\n.style-switcher .btn{margin-left:.25em;margin-right:.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/style_switcher/style_switcher.scss","\n.color-control input.text-input{max-width:7em;-ms-flex:1;flex:1\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/color_input/color_input.vue","\n.shadow-control{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center;margin-bottom:1em\n}\n.shadow-control .shadow-preview-container,.shadow-control .shadow-tweak{margin:5px 6px 0 0\n}\n.shadow-control .shadow-preview-container{-ms-flex:0;flex:0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.shadow-control .shadow-preview-container input[type=number]{width:5em;min-width:2em\n}\n.shadow-control .shadow-preview-container .x-shift-control,.shadow-control .shadow-preview-container .y-shift-control{display:-ms-flexbox;display:flex;-ms-flex:0;flex:0\n}\n.shadow-control .shadow-preview-container .x-shift-control[disabled=disabled] *,.shadow-control .shadow-preview-container .y-shift-control[disabled=disabled] *{opacity:.5\n}\n.shadow-control .shadow-preview-container .x-shift-control{-ms-flex-align:start;align-items:flex-start\n}\n.shadow-control .shadow-preview-container .x-shift-control .wrap,.shadow-control .shadow-preview-container input[type=range]{margin:0;width:15em;height:2em\n}\n.shadow-control .shadow-preview-container .y-shift-control{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:end;align-items:flex-end\n}\n.shadow-control .shadow-preview-container .y-shift-control .wrap{width:2em;height:15em\n}\n.shadow-control .shadow-preview-container .y-shift-control input[type=range]{transform-origin:1em 1em;transform:rotate(90deg)\n}\n.shadow-control .shadow-preview-container .preview-window{-ms-flex:1;flex:1;background-color:#999999;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;background-image:linear-gradient(45deg, #666 25%, transparent 25%),linear-gradient(-45deg, #666 25%, transparent 25%),linear-gradient(45deg, transparent 75%, #666 75%),linear-gradient(-45deg, transparent 75%, #666 75%);background-size:20px 20px;background-position:0 0, 0 10px, 10px -10px, -10px 0;border-radius:4px;border-radius:var(--inputRadius, 4px)\n}\n.shadow-control .shadow-preview-container .preview-window .preview-block{width:33%;height:33%;background-color:#121a24;background-color:var(--bg, #121a24);border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.shadow-control .shadow-tweak{-ms-flex:1;flex:1;min-width:280px\n}\n.shadow-control .shadow-tweak .id-control{-ms-flex-align:stretch;align-items:stretch\n}\n.shadow-control .shadow-tweak .id-control .select,.shadow-control .shadow-tweak .id-control .btn{min-width:1px;margin-right:5px\n}\n.shadow-control .shadow-tweak .id-control .btn{padding:0 .4em;margin:0 .1em\n}\n.shadow-control .shadow-tweak .id-control .select{-ms-flex:1;flex:1\n}\n.shadow-control .shadow-tweak .id-control .select select{-ms-flex-item-align:initial;-ms-grid-row-align:initial;align-self:initial\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/shadow_control/shadow_control.vue","\n.font-control input.custom-font{min-width:10em\n}\n.font-control.custom .select{border-top-right-radius:0;border-bottom-right-radius:0\n}\n.font-control.custom .custom-font{border-top-left-radius:0;border-bottom-left-radius:0\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/font_control/font_control.vue","\n.contrast-ratio{display:-ms-flexbox;display:flex;-ms-flex-pack:end;justify-content:flex-end;margin-top:-4px;margin-bottom:5px\n}\n.contrast-ratio .label{margin-right:1em\n}\n.contrast-ratio .rating{display:inline-block;text-align:center\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/contrast_ratio/contrast_ratio.vue","\n.import-export-container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:baseline;align-items:baseline;-ms-flex-pack:center;justify-content:center\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/export_import/export_import.vue","\n.registration-form{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:0.6em\n}\n.registration-form .container{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row\n}\n.registration-form .terms-of-service{-ms-flex:0 1 50%;flex:0 1 50%;margin:0.8em\n}\n.registration-form .text-fields{margin-top:0.6em;-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column\n}\n.registration-form .form-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.3em 0.0em 0.3em;line-height:24px;margin-bottom:1em\n}\n@keyframes shakeError{\n0%{transform:translateX(0)\n}\n15%{transform:translateX(0.375rem)\n}\n30%{transform:translateX(-0.375rem)\n}\n45%{transform:translateX(0.375rem)\n}\n60%{transform:translateX(-0.375rem)\n}\n75%{transform:translateX(0.375rem)\n}\n90%{transform:translateX(-0.375rem)\n}\n100%{transform:translateX(0)\n}\n}\n.registration-form .form-group--error{animation-name:shakeError;animation-duration:.6s;animation-timing-function:ease-in-out\n}\n.registration-form .form-group--error .form--label{color:#f04124;color:var(--cRed, #f04124)\n}\n.registration-form .form-error{margin-top:-0.7em;text-align:left\n}\n.registration-form .form-error span{font-size:12px\n}\n.registration-form .form-error ul{list-style:none;padding:0 0 0 5px;margin-top:0\n}\n.registration-form .form-error ul li::before{content:\"• \"\n}\n.registration-form form textarea{line-height:16px;resize:vertical\n}\n.registration-form .captcha{max-width:350px;margin-bottom:0.4em\n}\n.registration-form .btn{margin-top:0.6em;height:28px\n}\n.registration-form .error{text-align:center\n}\n@media all and (max-width: 959px){\n.registration-form .container{-ms-flex-direction:column-reverse;flex-direction:column-reverse\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/registration/registration.vue","\n.profile-edit .bio{margin:0\n}\n.profile-edit input[type=file]{padding:5px;height:auto\n}\n.profile-edit .banner{max-width:400px\n}\n.profile-edit .uploading{font-size:1.5em;margin:0.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_settings/user_settings.vue","\n.user-search-input-container{margin:0.5em;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center\n}\n.user-search-input-container .search-button{margin-left:0.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_search/user_search.vue","\n.notifications{padding-bottom:15em\n}\n.notifications .loadmore-error{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.notifications .notification{position:relative\n}\n.notifications .notification .notification-overlay{position:absolute;top:0;right:0;left:0;bottom:0;pointer-events:none\n}\n.notifications .notification.unseen .notification-overlay{background-image:linear-gradient(135deg, var(--badgeNotification, red) 4px, transparent 10px)\n}\n.notification{box-sizing:border-box;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222)\n}\n.notification .avatar-compact{width:32px;height:32px;box-shadow:var(--avatarStatusShadow);border-radius:10px;border-radius:var(--avatarAltRadius, 10px);overflow:hidden;line-height:0\n}\n.notification .avatar-compact.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.notification .avatar-compact.animated::before{display:none\n}\n.notification:hover .animated.avatar-compact canvas{display:none\n}\n.notification:hover .animated.avatar-compact img{visibility:visible\n}\n.notification .notification-usercard{margin:0\n}\n.notification .non-mention{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding:0.6em;min-width:0\n}\n.notification .non-mention .avatar-container{width:32px;height:32px\n}\n.notification .non-mention .status-el{padding:0\n}\n.notification .non-mention .status-el .status{padding:0.25em 0;color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n.notification .non-mention .status-el .status a{color:var(--faintLink)\n}\n.notification .non-mention .status-el .media-body{margin:0\n}\n.notification .follow-text{padding:0.5em 0\n}\n.notification .status-el{-ms-flex:1;flex:1\n}\n.notification time{white-space:nowrap\n}\n.notification .notification-right{-ms-flex:1;flex:1;padding-left:0.8em;min-width:0\n}\n.notification .notification-details{min-width:0px;word-wrap:break-word;line-height:18px;position:relative;overflow:hidden;width:100%;-ms-flex:1 1 0px;flex:1 1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap\n}\n.notification .notification-details .name-and-action{-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis\n}\n.notification .notification-details .username{font-weight:bolder;max-width:100%;text-overflow:ellipsis;white-space:nowrap\n}\n.notification .notification-details .username img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.notification .notification-details .timeago{float:right;font-size:12px\n}\n.notification .notification-details .icon-retweet.lit{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n.notification .notification-details .icon-user-plus.lit{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.notification .notification-details .icon-reply.lit{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.notification .notification-details .icon-star.lit{color:orange;color:orange;color:var(--cOrange, orange)\n}\n.notification .notification-details .status-content{margin:0;max-height:300px\n}\n.notification .notification-details h1{word-break:break-all;margin:0 0 0.3em;padding:0;font-size:1em;line-height:20px\n}\n.notification .notification-details h1 small{font-weight:lighter\n}\n.notification .notification-details p{margin:0;margin-top:0;margin-bottom:0.3em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/notifications/notifications.scss","\n.user-panel .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_panel/user_panel.vue","\n.login-form .btn{min-height:28px;width:10em\n}\n.login-form .error{text-align:center\n}\n.login-form .register{-ms-flex:1 1;flex:1 1\n}\n.login-form .login-bottom{margin-top:1.0em;display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/login_form/login_form.vue","\n.floating-chat{position:fixed;right:0px;bottom:0px;z-index:1000;max-width:25em\n}\n.chat-heading{cursor:pointer\n}\n.chat-heading .icon-comment-empty{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.chat-window{overflow-y:auto;overflow-x:hidden;max-height:20em\n}\n.chat-window-container{height:100%\n}\n.chat-message{display:-ms-flexbox;display:flex;padding:0.2em 0.5em\n}\n.chat-avatar img{height:24px;width:24px;border-radius:4px;border-radius:var(--avatarRadius, 4px);margin-right:0.5em;margin-top:0.25em\n}\n.chat-input{display:-ms-flexbox;display:flex\n}\n.chat-input textarea{-ms-flex:1;flex:1;margin:0.6em;min-height:3.5em;resize:none\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/chat_panel/chat_panel.vue","\n.features-panel li{line-height:24px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/features_panel/features_panel.vue","\n.tos-content{margin:1em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/terms_of_service_panel/terms_of_service_panel.vue","\n#app{background-size:cover;background-attachment:fixed;background-repeat:no-repeat;background-position:0 50px;min-height:100vh;max-width:100%;overflow:hidden\n}\ni{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none\n}\nh4{margin:0\n}\n#content{box-sizing:border-box;padding-top:60px;margin:auto;min-height:100vh;max-width:980px;background-color:rgba(0,0,0,0.15);-ms-flex-line-pack:start;align-content:flex-start\n}\n.text-center{text-align:center\n}\nbody{font-family:sans-serif;font-family:var(--interfaceFont, sans-serif);font-size:14px;margin:0;color:#b9b9ba;color:var(--text, #b9b9ba);max-width:100vw;overflow-x:hidden\n}\na{text-decoration:none;color:#d8a070;color:var(--link, #d8a070)\n}\nbutton{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#b9b9ba;color:var(--btnText, #b9b9ba);background-color:#182230;background-color:var(--btn, #182230);border:none;border-radius:4px;border-radius:var(--btnRadius, 4px);cursor:pointer;box-shadow:0px 0px 2px 0px #000,0px 1px 0px 0px rgba(255,255,255,0.2) inset,0px -1px 0px 0px rgba(0,0,0,0.2) inset;box-shadow:var(--buttonShadow);font-size:14px;font-family:sans-serif;font-family:var(--interfaceFont, sans-serif)\n}\nbutton i[class*=icon-]{color:#b9b9ba;color:var(--btnText, #b9b9ba)\n}\nbutton::-moz-focus-inner{border:none\n}\nbutton:hover{box-shadow:0px 0px 4px rgba(255,255,255,0.3);box-shadow:var(--buttonHoverShadow)\n}\nbutton:active{box-shadow:0px 0px 4px 0px rgba(255,255,255,0.3),0px 1px 0px 0px rgba(0,0,0,0.2) inset,0px -1px 0px 0px rgba(255,255,255,0.2) inset;box-shadow:var(--buttonPressedShadow)\n}\nbutton:disabled{cursor:not-allowed;opacity:0.5\n}\nbutton.pressed{color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5));background-color:#121a24;background-color:var(--bg, #121a24)\n}\nlabel.select{padding:0\n}\ninput,textarea,.select{border:none;border-radius:4px;border-radius:var(--inputRadius, 4px);box-shadow:0px 1px 0px 0px rgba(0,0,0,0.2) inset,0px -1px 0px 0px rgba(255,255,255,0.2) inset,0px 0px 2px 0px #000 inset;box-shadow:var(--inputShadow);background-color:#182230;background-color:var(--input, #182230);color:#b9b9ba;color:var(--inputText, #b9b9ba);font-family:sans-serif;font-family:var(--inputFont, sans-serif);font-size:14px;padding:8px .5em;box-sizing:border-box;display:inline-block;position:relative;height:28px;line-height:16px;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none\n}\ninput:disabled,input[disabled=disabled],textarea:disabled,textarea[disabled=disabled],.select:disabled,.select[disabled=disabled]{cursor:not-allowed;opacity:0.5\n}\ninput .icon-down-open,textarea .icon-down-open,.select .icon-down-open{position:absolute;top:0;bottom:0;right:5px;height:100%;color:#b9b9ba;color:var(--text, #b9b9ba);line-height:28px;z-index:0;pointer-events:none\n}\ninput select,textarea select,.select select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:#b9b9ba;color:var(--text, #b9b9ba);margin:0;padding:0 2em 0 .2em;font-family:sans-serif;font-family:var(--inputFont, sans-serif);font-size:14px;width:100%;z-index:1;height:28px;line-height:16px\n}\ninput[type=range],textarea[type=range],.select[type=range]{background:none;border:none;margin:0;box-shadow:none;-ms-flex:1;flex:1\n}\ninput[type=radio],input[type=checkbox],textarea[type=radio],textarea[type=checkbox],.select[type=radio],.select[type=checkbox]{display:none\n}\ninput[type=radio]:checked+label::before,input[type=checkbox]:checked+label::before,textarea[type=radio]:checked+label::before,textarea[type=checkbox]:checked+label::before,.select[type=radio]:checked+label::before,.select[type=checkbox]:checked+label::before{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\ninput[type=radio]:disabled,input[type=radio]:disabled+label,input[type=radio]:disabled+label::before,input[type=checkbox]:disabled,input[type=checkbox]:disabled+label,input[type=checkbox]:disabled+label::before,textarea[type=radio]:disabled,textarea[type=radio]:disabled+label,textarea[type=radio]:disabled+label::before,textarea[type=checkbox]:disabled,textarea[type=checkbox]:disabled+label,textarea[type=checkbox]:disabled+label::before,.select[type=radio]:disabled,.select[type=radio]:disabled+label,.select[type=radio]:disabled+label::before,.select[type=checkbox]:disabled,.select[type=checkbox]:disabled+label,.select[type=checkbox]:disabled+label::before{opacity:.5\n}\ninput[type=radio]+label::before,input[type=checkbox]+label::before,textarea[type=radio]+label::before,textarea[type=checkbox]+label::before,.select[type=radio]+label::before,.select[type=checkbox]+label::before{display:inline-block;content:'✔';transition:color 200ms;width:1.1em;height:1.1em;border-radius:2px;border-radius:var(--checkboxRadius, 2px);box-shadow:0px 0px 2px black inset;box-shadow:var(--inputShadow);margin-right:.5em;background-color:#182230;background-color:var(--input, #182230);vertical-align:top;text-align:center;line-height:1.1em;font-size:1.1em;box-sizing:border-box;color:transparent;overflow:hidden;box-sizing:border-box\n}\noption{color:#b9b9ba;color:var(--text, #b9b9ba);background-color:#121a24;background-color:var(--bg, #121a24)\n}\ni[class*=icon-]{color:#666;color:var(--icon, #666)\n}\n.container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0 10px 0 10px\n}\n.item{-ms-flex:1;flex:1;line-height:50px;height:50px;overflow:hidden;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.item .nav-icon{margin-left:0.4em\n}\n.item.right{-ms-flex-pack:end;justify-content:flex-end\n}\n.auto-size{-ms-flex:1;flex:1\n}\n.nav-bar{padding:0;width:100%;-ms-flex-align:center;align-items:center;position:fixed;height:50px\n}\n.nav-bar .logo{display:-ms-flexbox;display:flex;position:absolute;top:0;bottom:0;left:0;right:0;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:center;justify-content:center;-ms-flex:0 0 auto;flex:0 0 auto;z-index:-1;transition:opacity;transition-timing-function:ease-out;transition-duration:100ms\n}\n.nav-bar .logo .mask{-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;mask-size:contain;background-color:#182230;background-color:var(--topBarText, #182230);position:absolute;top:0;bottom:0;left:0;right:0\n}\n.nav-bar .logo img{height:100%;object-fit:contain;display:block;-ms-flex:0;flex:0\n}\n.nav-bar .inner-nav{margin:auto;box-sizing:border-box;padding-left:10px;padding-right:10px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-preferred-size:970px;flex-basis:970px;height:50px\n}\n.nav-bar .inner-nav a,.nav-bar .inner-nav a i{color:#d8a070;color:var(--topBarLink, #d8a070)\n}\nmain-router{-ms-flex:1;flex:1\n}\n.status.compact{color:rgba(0,0,0,0.42);font-weight:300\n}\n.status.compact p{margin:0;font-size:0.8em\n}\n.panel{display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;margin:0.5em;background-color:#121a24;background-color:var(--bg, #121a24)\n}\n.panel::after,.panel{border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.panel::after{content:'';position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:none;box-shadow:1px 1px 4px rgba(0,0,0,0.6);box-shadow:var(--panelShadow)\n}\n.panel-body:empty::before{content:\"¯\\\\_(ツ)_/¯\";display:block;margin:1em;text-align:center\n}\n.panel-heading{display:-ms-flexbox;display:flex;border-radius:10px 10px 0 0;border-radius:var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0;background-size:cover;padding:.6em .6em;text-align:left;line-height:28px;color:var(--panelText);background-color:#182230;background-color:var(--panel, #182230);-ms-flex-align:baseline;align-items:baseline;box-shadow:var(--panelHeaderShadow)\n}\n.panel-heading .title{-ms-flex:1 0 auto;flex:1 0 auto;font-size:1.3em\n}\n.panel-heading .faint{background-color:transparent;color:rgba(185,185,186,0.5);color:var(--panelFaint, rgba(185,185,186,0.5))\n}\n.panel-heading .alert{white-space:nowrap;text-overflow:ellipsis;overflow-x:hidden\n}\n.panel-heading button{-ms-flex-negative:0;flex-shrink:0\n}\n.panel-heading button,.panel-heading .alert{line-height:21px;min-height:0;box-sizing:border-box;margin:0;margin-left:.25em;min-width:1px;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.panel-heading a{color:#d8a070;color:var(--panelLink, #d8a070)\n}\n.panel-heading.stub{border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.panel-footer{border-radius:0 0 10px 10px;border-radius:0 0 var(--panelRadius, 10px) var(--panelRadius, 10px)\n}\n.panel-footer a{color:#d8a070;color:var(--panelLink, #d8a070)\n}\n.panel-body>p{line-height:18px;padding:1em;margin:0\n}\n.container>*{min-width:0px\n}\n.fa{color:grey\n}\nnav{z-index:1000;color:var(--topBarText);background-color:#182230;background-color:var(--topBar, #182230);color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5));box-shadow:0px 0px 4px rgba(0,0,0,0.6);box-shadow:var(--topBarShadow)\n}\nnav .back-button{display:block;max-width:99px;transition-property:opacity, max-width;transition-duration:300ms;transition-timing-function:ease-out\n}\nnav .back-button i{margin:0 1em\n}\nnav .back-button.hidden{opacity:0;max-width:5px\n}\n.menu-button{display:none;position:relative\n}\n.alert-dot{border-radius:100%;height:8px;width:8px;position:absolute;left:calc(50% - 4px);top:calc(50% - 4px);margin-left:6px;margin-top:-6px;background-color:red;background-color:var(--badgeNotification, red)\n}\n.fade-enter-active,.fade-leave-active{transition:opacity .2s\n}\n.fade-enter,.fade-leave-active{opacity:0\n}\n.main{-ms-flex-preferred-size:60%;flex-basis:60%;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1\n}\n.sidebar-bounds{-ms-flex:0;flex:0;-ms-flex-preferred-size:35%;flex-basis:35%\n}\n.sidebar-flexer{-ms-flex:1;flex:1;-ms-flex-preferred-size:345px;flex-basis:345px;width:365px\n}\n.mobile-shown{display:none\n}\n.panel-switcher{display:none;width:100%;height:46px\n}\n.panel-switcher button{display:block;-ms-flex:1;flex:1;max-height:32px;margin:0.5em;padding:0.5em\n}\n@media all and (min-width: 960px){\nbody{overflow-y:scroll\n}\nnav .back-button{display:none\n}\n.sidebar-bounds{overflow:hidden;max-height:100vh;width:345px;position:fixed;margin-top:-10px\n}\n.sidebar-bounds .sidebar-scroller{height:96vh;width:365px;padding-top:10px;padding-right:50px;overflow-x:hidden;overflow-y:scroll\n}\n.sidebar-bounds .sidebar{width:345px\n}\n.sidebar-flexer{max-height:96vh;-ms-flex-negative:0;flex-shrink:0;-ms-flex-positive:0;flex-grow:0\n}\n}\n.badge{display:inline-block;border-radius:99px;min-width:22px;max-width:22px;min-height:22px;max-height:22px;font-size:15px;line-height:22px;text-align:center;vertical-align:middle;white-space:nowrap;padding:0\n}\n.badge.badge-notification{background-color:red;background-color:var(--badgeNotification, red);color:white;color:var(--badgeNotificationText, #fff)\n}\n.alert{margin:0.35em;padding:0.25em;border-radius:5px;border-radius:var(--tooltipRadius, 5px);min-height:28px;line-height:28px\n}\n.alert.error{background-color:rgba(211,16,20,0.5);background-color:var(--alertError, rgba(211,16,20,0.5));color:#b9b9ba;color:var(--alertErrorText, #b9b9ba)\n}\n.panel-heading .alert.error{color:#b9b9ba;color:var(--alertErrorPanelText, #b9b9ba)\n}\n.faint{color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n@media all and (min-width: 959px){\n.logo{opacity:1 !important\n}\n}\n.item.right{text-align:right\n}\n.visibility-tray{font-size:1.2em;padding:3px;cursor:pointer\n}\n.visibility-tray .selected{color:#b9b9ba;color:var(--lightText, #b9b9ba)\n}\n.visibility-tray .text-format{float:right\n}\n.visibility-tray div{padding-top:5px\n}\n.visibility-notice{padding:.5em;border:1px solid rgba(185,185,186,0.5);border:1px solid var(--faint, rgba(185,185,186,0.5));border-radius:4px;border-radius:var(--inputRadius, 4px)\n}\n@media all and (max-width: 959px){\n.mobile-hidden{display:none\n}\n.panel-switcher{display:-ms-flexbox;display:flex\n}\n.container{padding:0\n}\n.panel{margin:0.5em 0 0.5em 0\n}\n.button-icon{font-size:1.2em\n}\n.status .status-actions div{max-width:4em\n}\n.menu-button{display:block;margin-right:0.8em\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/App.scss","\n.nav-panel .panel{overflow:hidden\n}\n.nav-panel ul{list-style:none;margin:0;padding:0\n}\n.nav-panel li{border-bottom:1px solid;border-color:#222;border-color:var(--border, #222);padding:0\n}\n.nav-panel li:first-child a{border-top-right-radius:10px;border-top-right-radius:var(--panelRadius, 10px);border-top-left-radius:10px;border-top-left-radius:var(--panelRadius, 10px)\n}\n.nav-panel li:last-child a{border-bottom-right-radius:10px;border-bottom-right-radius:var(--panelRadius, 10px);border-bottom-left-radius:10px;border-bottom-left-radius:var(--panelRadius, 10px)\n}\n.nav-panel li:last-child{border:none\n}\n.nav-panel a{display:block;padding:0.8em 0.85em\n}\n.nav-panel a:hover{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.nav-panel a.router-link-active{font-weight:bolder;background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.nav-panel a.router-link-active:hover{text-decoration:underline\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/nav_panel/nav_panel.vue","\n.user-finder-container{max-width:100%;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:baseline;align-items:baseline;vertical-align:baseline\n}\n.user-finder-container .user-finder-input,.user-finder-container .search-button{height:29px\n}\n.user-finder-container .user-finder-input{max-width:calc(100% - 30px - 30px - 20px)\n}\n.user-finder-container .search-button{margin-left:.5em;margin-right:.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_finder/user_finder.vue","\n.who-to-follow *{vertical-align:middle\n}\n.who-to-follow img{width:32px;height:32px\n}\n.who-to-follow{padding:0.5em 1em 0.5em 1em;margin:0px;line-height:40px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/who_to_follow_panel/who_to_follow_panel.vue","\n.side-drawer-container{position:fixed;z-index:1000;top:0;left:0;width:100%;height:100%;display:-ms-flexbox;display:flex;-ms-flex-align:stretch;align-items:stretch\n}\n.side-drawer-container-open{transition-delay:0.0s;transition-property:left\n}\n.side-drawer-container-closed{left:-100%;transition-delay:0.5s;transition-property:left\n}\n.side-drawer-click-outside{-ms-flex:1 1 100%;flex:1 1 100%\n}\n.side-drawer{overflow-x:hidden;transition:0.5s;transition-timing-function:cubic-bezier(0, 1, 0.5, 1);margin:0 0 0 -100px;padding:0 0 1em 100px;width:80%;max-width:20em;-ms-flex:0 0 80%;flex:0 0 80%;box-shadow:1px 1px 4px rgba(0,0,0,0.6);box-shadow:var(--panelShadow);background-color:#121a24;background-color:var(--bg, #121a24)\n}\n.side-drawer-click-outside-closed{-ms-flex:0 0 0px;flex:0 0 0\n}\n.side-drawer-closed{margin:0 0 0 calc(-100% - 100px)\n}\n.side-drawer-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch;display:-ms-flexbox;display:flex;min-height:7em;padding:0;margin:0\n}\n.side-drawer-heading .profile-panel-background{border-radius:0\n}\n.side-drawer-heading .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.side-drawer ul{list-style:none;margin:0;padding:0;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222);margin:0.2em 0\n}\n.side-drawer ul:last-child{border:0\n}\n.side-drawer li{padding:0\n}\n.side-drawer li a{display:block;padding:0.5em 0.85em\n}\n.side-drawer li a:hover{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/side_drawer/side_drawer.vue"],"sourceRoot":""}
\ No newline at end of file
diff --git a/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css b/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css
deleted file mode 100644
index b089645a1..000000000
Binary files a/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css and /dev/null differ
diff --git a/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css.map b/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css.map
deleted file mode 100644
index 8823d3962..000000000
--- a/priv/static/static/css/app.c52cbb57296d5c682ff405d562e83a9b.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["webpack:///webpack:///src/components/timeline/timeline.vue","webpack:///webpack:///src/components/status/status.vue","webpack:///webpack:///src/components/attachment/attachment.vue","webpack:///webpack:///src/components/still-image/still-image.vue","webpack:///webpack:///src/components/favorite_button/favorite_button.vue","webpack:///webpack:///src/components/retweet_button/retweet_button.vue","webpack:///webpack:///src/components/delete_button/delete_button.vue","webpack:///webpack:///src/components/post_status_form/post_status_form.vue","webpack:///webpack:///src/components/media_upload/media_upload.vue","webpack:///webpack:///src/components/user_card_content/user_card_content.vue","webpack:///webpack:///src/components/status_or_conversation/status_or_conversation.vue","webpack:///webpack:///src/components/user_card/user_card.vue","webpack:///webpack:///src/components/user_profile/user_profile.vue","webpack:///webpack:///src/components/settings/settings.vue","webpack:///webpack:///src/components/tab_switcher/src/components/tab_switcher/tab_switcher.scss","webpack:///webpack:///src/components/style_switcher/style_switcher.scss","webpack:///webpack:///src/components/color_input/color_input.vue","webpack:///webpack:///src/components/shadow_control/shadow_control.vue","webpack:///webpack:///src/components/font_control/font_control.vue","webpack:///webpack:///src/components/contrast_ratio/contrast_ratio.vue","webpack:///webpack:///src/components/export_import/export_import.vue","webpack:///webpack:///src/components/registration/registration.vue","webpack:///webpack:///src/components/user_settings/user_settings.vue","webpack:///webpack:///src/components/user_search/user_search.vue","webpack:///webpack:///src/components/notifications/notifications.scss","webpack:///webpack:///src/components/user_panel/user_panel.vue","webpack:///webpack:///src/components/login_form/login_form.vue","webpack:///webpack:///src/components/chat_panel/chat_panel.vue","webpack:///webpack:///src/App.scss","webpack:///webpack:///src/components/nav_panel/nav_panel.vue","webpack:///webpack:///src/components/user_finder/user_finder.vue","webpack:///webpack:///src/components/features_panel/features_panel.vue","webpack:///webpack:///src/components/who_to_follow_panel/who_to_follow_panel.vue","webpack:///webpack:///src/components/side_drawer/side_drawer.vue"],"names":[],"mappings":"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","file":"static/css/app.c52cbb57296d5c682ff405d562e83a9b.css","sourcesContent":["\n.timeline .loadmore-text{opacity:1\n}\n.new-status-notification{position:relative;margin-top:-1px;font-size:1.1em;border-width:1px 0 0 0;border-style:solid;border-color:var(--border, #222);padding:10px;z-index:1;background-color:#182230;background-color:var(--panel, #182230)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/timeline/timeline.vue","\n.status-body{-ms-flex:1;flex:1;min-width:0\n}\n.status-preview.status-el{border-style:solid;border-width:1px;border-color:#222;border-color:var(--border, #222)\n}\n.status-preview-container{position:relative;max-width:100%\n}\n.status-preview{position:absolute;max-width:95%;display:-ms-flexbox;display:flex;background-color:#121a24;background-color:var(--bg, #121a24);border-color:#222;border-color:var(--border, #222);border-style:solid;border-width:1px;border-radius:5px;border-radius:var(--tooltipRadius, 5px);box-shadow:2px 2px 3px rgba(0,0,0,0.5);box-shadow:var(--popupShadow);margin-top:0.25em;margin-left:0.5em;z-index:50\n}\n.status-preview .status{-ms-flex:1;flex:1;border:0;min-width:15em\n}\n.status-preview-loading{display:block;min-width:15em;padding:1em;text-align:center;border-width:1px;border-style:solid\n}\n.status-preview-loading i{font-size:2em\n}\n.status-el{-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;border-left-width:0px;line-height:18px;min-width:0;border-color:#222;border-color:var(--border, #222);border-left:4px red;border-left:4px var(--cRed, red)\n}\n.status-el_focused{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.timeline .status-el{border-bottom-width:1px;border-bottom-style:solid\n}\n.status-el .media-body{-ms-flex:1;flex:1;padding:0;margin:0 0 0.25em 0.8em\n}\n.status-el .usercard{margin-bottom:.7em\n}\n.status-el .media-heading{-ms-flex-wrap:nowrap;flex-wrap:nowrap;line-height:18px\n}\n.status-el .media-heading-left{padding:0;vertical-align:bottom;-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.status-el .media-heading-left small{font-weight:lighter\n}\n.status-el .media-heading-left h4{white-space:nowrap;font-size:14px;margin-right:0.25em;overflow:hidden;text-overflow:ellipsis\n}\n.status-el .media-heading-left .name-and-links{padding:0;-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:baseline;align-items:baseline\n}\n.status-el .media-heading-left .name-and-links .user-name{margin-right:.45em\n}\n.status-el .media-heading-left .name-and-links .user-name img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.status-el .media-heading-left .links{display:-ms-flexbox;display:flex;font-size:12px;color:#d8a070;color:var(--link, #d8a070);max-width:100%\n}\n.status-el .media-heading-left .links a{max-width:100%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap\n}\n.status-el .media-heading-left .reply-info{display:-ms-flexbox;display:flex\n}\n.status-el .media-heading-left .replies{line-height:16px\n}\n.status-el .media-heading-left .reply-link{margin-right:0.2em\n}\n.status-el .media-heading-right{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-negative:0;flex-shrink:0;-ms-flex-wrap:nowrap;flex-wrap:nowrap;margin-left:.25em;-ms-flex-item-align:baseline;align-self:baseline\n}\n.status-el .media-heading-right .timeago{margin-right:0.2em;font-size:12px;-ms-flex-item-align:last baseline;-ms-grid-row-align:last baseline;align-self:last baseline\n}\n.status-el .media-heading-right>*{margin-left:0.2em\n}\n.status-el .media-heading-right a:hover i{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.status-el a{display:inline-block;word-break:break-all\n}\n.status-el .tall-status{position:relative;height:220px;overflow-x:hidden;overflow-y:hidden\n}\n.status-el .tall-status-hider{position:absolute;height:70px;margin-top:150px;width:100%;text-align:center;line-height:110px;background:linear-gradient(to bottom, transparent, #121a24 80%);background:linear-gradient(to bottom, transparent, var(--bg, #121a24) 80%)\n}\n.status-el .tall-status-hider_focused{background:linear-gradient(to bottom, transparent, #151e2a 80%);background:linear-gradient(to bottom, transparent, var(--lightBg, #151e2a) 80%)\n}\n.status-el .status-unhider,.status-el .cw-status-hider{width:100%;text-align:center\n}\n.status-el .status-content{margin-right:0.5em;font-family:var(--postFont, sans-serif)\n}\n.status-el .status-content img,.status-el .status-content video{max-width:100%;max-height:400px;vertical-align:middle;object-fit:contain\n}\n.status-el .status-content blockquote{margin:0.2em 0 0.2em 2em;font-style:italic\n}\n.status-el .status-content pre{overflow:auto\n}\n.status-el .status-content code,.status-el .status-content samp,.status-el .status-content kbd,.status-el .status-content var,.status-el .status-content pre{font-family:var(--postCodeFont, monospace)\n}\n.status-el .status-content p{margin:0;margin-top:0.2em;margin-bottom:0.5em\n}\n.status-el .status-content h1{font-size:1.1em;line-height:1.2em;margin:1.4em 0\n}\n.status-el .status-content h2{font-size:1.1em;margin:1.0em 0\n}\n.status-el .status-content h3{font-size:1em;margin:1.2em 0\n}\n.status-el .status-content h4{margin:1.1em 0\n}\n.status-el .retweet-info{padding:0.4em 0.6em 0 0.6em;margin:0\n}\n.status-el .retweet-info .avatar{border-radius:10px;border-radius:var(--avatarAltRadius, 10px);margin-left:28px;width:20px;height:20px\n}\n.status-el .retweet-info .media-body{font-size:1em;line-height:22px;display:-ms-flexbox;display:flex;-ms-flex-line-pack:center;align-content:center;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.status-el .retweet-info .media-body .user-name{font-weight:bold\n}\n.status-el .retweet-info .media-body .user-name img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.status-el .retweet-info .media-body i{padding:0 0.2em\n}\n.status-el .retweet-info .media-body a{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\n}\n.status-fadein{animation-duration:0.4s;animation-name:fadein\n}\n@keyframes fadein{\nfrom{opacity:0\n}\nto{opacity:1\n}\n}\n.greentext{color:green\n}\n.status-conversation{border-left-style:solid\n}\n.status-actions{width:100%;display:-ms-flexbox;display:flex\n}\n.status-actions div,.status-actions favorite-button{padding-top:0.25em;max-width:6em;-ms-flex:1;flex:1\n}\n.icon-reply:hover{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.icon-reply.icon-reply-active{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.status .avatar-compact{width:32px;height:32px;box-shadow:var(--avatarStatusShadow);border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.status .avatar-compact.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.avatar.still-image{width:48px;height:48px;box-shadow:var(--avatarStatusShadow);border-radius:4px;border-radius:var(--avatarRadius, 4px);overflow:hidden;position:relative\n}\n.avatar.still-image.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.avatar.still-image img{width:100%;height:100%\n}\n.avatar.still-image.animated::before{display:none\n}\n.status:hover .animated.avatar canvas{display:none\n}\n.status:hover .animated.avatar img{visibility:visible\n}\n.status{display:-ms-flexbox;display:flex;padding:0.6em\n}\n.status.is-retweet{padding-top:0.1em\n}\n.status-conversation:last-child{border-bottom:none\n}\n.muted{padding:0.25em 0.5em\n}\n.muted button{margin-left:auto\n}\n.muted .muteWords{margin-left:10px\n}\na.unmute{display:block;margin-left:auto\n}\n.reply-left{-ms-flex:0;flex:0;min-width:48px\n}\n.reply-body{-ms-flex:1;flex:1\n}\n.timeline>.status-el:last-child{border-bottom-radius:0 0 10px 10px;border-radius:0 0 var(--panelRadius, 10px) var(--panelRadius, 10px);border-bottom:none\n}\n@media all and (max-width: 960px){\n.status-el .retweet-info .avatar{margin-left:20px\n}\n.status{max-width:100%\n}\n.status .avatar{width:40px;height:40px\n}\n.status .avatar-compact{width:32px;height:32px\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/status/status.vue","\n.attachments{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.attachments .attachment.media-upload-container{-ms-flex:0 0 auto;flex:0 0 auto;max-height:300px;max-width:100%\n}\n.attachments .placeholder{margin-right:0.5em\n}\n.attachments .nsfw-placeholder{cursor:pointer\n}\n.attachments .nsfw-placeholder.loading{cursor:progress\n}\n.attachments .small-attachment{max-height:100px\n}\n.attachments .small-attachment.image,.attachments .small-attachment.video{max-width:35%\n}\n.attachments .attachment{position:relative;-ms-flex:1 0 30%;flex:1 0 30%;margin:0.5em 0.7em 0.6em 0.0em;-ms-flex-item-align:start;align-self:flex-start;line-height:0;border-style:solid;border-width:1px;border-radius:10px;border-radius:var(--attachmentRadius, 10px);border-color:#222;border-color:var(--border, #222);overflow:hidden\n}\n.attachments .fullwidth{-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.attachments.video{line-height:0\n}\n.attachments.html{-ms-flex-preferred-size:90%;flex-basis:90%;width:100%;display:-ms-flexbox;display:flex\n}\n.attachments .hider{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);font-weight:bold;z-index:4;line-height:1;border-radius:5px;border-radius:var(--tooltipRadius, 5px)\n}\n.attachments .small{max-height:100px\n}\n.attachments video{max-height:500px;height:100%;width:100%;z-index:0\n}\n.attachments audio{width:100%\n}\n.attachments img.media-upload{line-height:0;max-height:300px;max-width:100%\n}\n.attachments .oembed{line-height:1.2em;-ms-flex:1 0 100%;flex:1 0 100%;width:100%;margin-right:15px;display:-ms-flexbox;display:flex\n}\n.attachments .oembed img{width:100%\n}\n.attachments .oembed .image{-ms-flex:1;flex:1\n}\n.attachments .oembed .image img{border:0px;border-radius:5px;height:100%;object-fit:cover\n}\n.attachments .oembed .text{-ms-flex:2;flex:2;margin:8px;word-break:break-all\n}\n.attachments .oembed .text h1{font-size:14px;margin:0px\n}\n.attachments .image-attachment{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1\n}\n.attachments .image-attachment.hidden{display:none\n}\n.attachments .image-attachment .still-image{width:100%;height:100%\n}\n.attachments .image-attachment .small img{max-height:100px\n}\n.attachments .image-attachment img{object-fit:contain;width:100%;height:100%;max-height:500px;image-orientation:from-image\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/attachment/attachment.vue","\n.still-image{position:relative;line-height:0;overflow:hidden;width:100%;height:100%\n}\n.still-image:hover canvas{display:none\n}\n.still-image img{width:100%;height:100%;object-fit:contain\n}\n.still-image.animated:hover::before,.still-image.animated img{visibility:hidden\n}\n.still-image.animated:hover img{visibility:visible\n}\n.still-image.animated::before{content:'gif';position:absolute;line-height:10px;font-size:10px;top:5px;left:5px;background:rgba(127,127,127,0.5);color:#FFF;display:block;padding:2px 4px;border-radius:5px;border-radius:var(--tooltipRadius, 5px);z-index:2\n}\n.still-image canvas{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;object-fit:contain\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/still-image/still-image.vue","\n.fav-active{cursor:pointer;animation-duration:0.6s\n}\n.fav-active:hover{color:orange;color:var(--cOrange, orange)\n}\n.favorite-button.icon-star{color:orange;color:var(--cOrange, orange)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/favorite_button/favorite_button.vue","\n.rt-active{cursor:pointer;animation-duration:0.6s\n}\n.rt-active:hover{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n.icon-retweet.retweeted{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/retweet_button/retweet_button.vue","\n.icon-cancel,.delete-status{cursor:pointer\n}\n.icon-cancel:hover,.delete-status:hover{color:red;color:var(--cRed, red)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/delete_button/delete_button.vue","\n.tribute-container ul{padding:0px\n}\n.tribute-container ul li{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center\n}\n.tribute-container img{padding:3px;width:16px;height:16px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.post-status-form .form-bottom,.login .form-bottom{display:-ms-flexbox;display:flex;padding:0.5em;height:32px\n}\n.post-status-form .form-bottom button,.login .form-bottom button{width:10em\n}\n.post-status-form .form-bottom p,.login .form-bottom p{margin:0.35em;padding:0.35em;display:-ms-flexbox;display:flex\n}\n.post-status-form .error,.login .error{text-align:center\n}\n.post-status-form .media-upload-wrapper,.login .media-upload-wrapper{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;min-width:50px;margin-right:.2em;margin-bottom:.5em\n}\n.post-status-form .media-upload-wrapper .icon-cancel,.login .media-upload-wrapper .icon-cancel{display:inline-block;position:static;margin:0;padding-bottom:0;margin-left:10px;margin-left:var(--attachmentRadius, 10px);background-color:#182230;background-color:var(--btn, #182230);border-bottom-left-radius:0;border-bottom-right-radius:0\n}\n.post-status-form .attachments,.login .attachments{padding:0 0.5em\n}\n.post-status-form .attachments .attachment,.login .attachments .attachment{margin:0;position:relative;-ms-flex:0 0 auto;flex:0 0 auto;border:1px solid #222;border:1px solid var(--border, #222);text-align:center\n}\n.post-status-form .attachments .attachment audio,.login .attachments .attachment audio{min-width:300px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.post-status-form .attachments .attachment a,.login .attachments .attachment a{display:block;text-align:left;line-height:1.2;padding:.5em\n}\n.post-status-form .attachments i,.login .attachments i{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);border-radius:10px;border-radius:var(--attachmentRadius, 10px);font-weight:bold\n}\n.post-status-form .btn,.login .btn{cursor:pointer\n}\n.post-status-form .btn[disabled],.login .btn[disabled]{cursor:not-allowed\n}\n.post-status-form form,.login form{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.6em\n}\n.post-status-form .form-group,.login .form-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.3em 0.5em 0.6em;line-height:24px\n}\n.post-status-form form textarea.form-cw,.login form textarea.form-cw{line-height:16px;resize:none;overflow:hidden;transition:min-height 200ms 100ms;min-height:1px\n}\n.post-status-form form textarea.form-control,.login form textarea.form-control{line-height:16px;resize:none;overflow:hidden;transition:min-height 200ms 100ms;min-height:1px;box-sizing:content-box\n}\n.post-status-form form textarea.form-control:focus,.login form textarea.form-control:focus{min-height:48px\n}\n.post-status-form .btn,.login .btn{cursor:pointer\n}\n.post-status-form .btn[disabled],.login .btn[disabled]{cursor:not-allowed\n}\n.post-status-form .icon-cancel,.login .icon-cancel{cursor:pointer;z-index:4\n}\n.post-status-form .autocomplete-panel,.login .autocomplete-panel{margin:0 0.5em 0 0.5em;border-radius:5px;border-radius:var(--tooltipRadius, 5px);position:absolute;z-index:1;box-shadow:1px 2px 4px rgba(0,0,0,0.5);box-shadow:var(--popupShadow);min-width:75%;background:#121a24;background:var(--bg, #121a24);color:#b9b9ba;color:var(--lightText, #b9b9ba)\n}\n.post-status-form .autocomplete,.login .autocomplete{cursor:pointer;padding:0.2em 0.4em 0.2em 0.4em;border-bottom:1px solid rgba(0,0,0,0.4);display:-ms-flexbox;display:flex\n}\n.post-status-form .autocomplete img,.login .autocomplete img{width:24px;height:24px;border-radius:4px;border-radius:var(--avatarRadius, 4px);object-fit:contain\n}\n.post-status-form .autocomplete span,.login .autocomplete span{line-height:24px;margin:0 0.1em 0 0.2em\n}\n.post-status-form .autocomplete small,.login .autocomplete small{margin-left:.5em;color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n.post-status-form .autocomplete.highlighted,.login .autocomplete.highlighted{background-color:#182230;background-color:var(--lightBg, #182230)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/post_status_form/post_status_form.vue","\n.media-upload {\n font-size: 26px;\n -ms-flex: 1;\n flex: 1;\n}\n.icon-upload {\n cursor: pointer;\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/media_upload/media_upload.vue","\n.profile-panel-background{background-size:cover;border-radius:10px;border-radius:var(--panelRadius, 10px);overflow:hidden;border-bottom-left-radius:0;border-bottom-right-radius:0\n}\n.profile-panel-background .panel-heading{padding:.6em 0;text-align:center;box-shadow:none\n}\n.profile-panel-body{word-wrap:break-word;background:linear-gradient(to bottom, transparent, #121a24 80%);background:linear-gradient(to bottom, transparent, var(--bg, #121a24) 80%)\n}\n.profile-panel-body .profile-bio{text-align:center\n}\n.user-info{color:#b9b9ba;color:var(--lightText, #b9b9ba);padding:0 26px\n}\n.user-info .container{padding:16px 0 6px;display:-ms-flexbox;display:flex;max-height:56px\n}\n.user-info .container .avatar{border-radius:4px;border-radius:var(--avatarRadius, 4px);-ms-flex:1 0 100%;flex:1 0 100%;width:56px;height:56px;box-shadow:0px 1px 8px rgba(0,0,0,0.75);box-shadow:var(--avatarShadow);object-fit:cover\n}\n.user-info .container .avatar.better-shadow{box-shadow:var(--avatarShadowInset);filter:var(--avatarShadowFilter)\n}\n.user-info .container .avatar.animated::before{display:none\n}\n.user-info:hover .animated.avatar canvas{display:none\n}\n.user-info:hover .animated.avatar img{visibility:visible\n}\n.user-info .usersettings{color:#b9b9ba;color:var(--lightText, #b9b9ba);opacity:.8\n}\n.user-info .name-and-screen-name{display:block;margin-left:0.6em;text-align:left;text-overflow:ellipsis;white-space:nowrap;-ms-flex:1 1 0px;flex:1 1 0;z-index:1\n}\n.user-info .name-and-screen-name img{width:26px;height:26px;vertical-align:middle;object-fit:contain\n}\n.user-info .name-and-screen-name .top-line{display:-ms-flexbox;display:flex\n}\n.user-info .user-name{text-overflow:ellipsis;overflow:hidden;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-screen-name{color:#b9b9ba;color:var(--lightText, #b9b9ba);display:inline-block;font-weight:light;font-size:15px;padding-right:0.1em;width:100%;display:-ms-flexbox;display:flex\n}\n.user-info .user-screen-name .dailyAvg{min-width:1px;-ms-flex:0 0 auto;flex:0 0 auto\n}\n.user-info .user-screen-name .handle{min-width:1px;-ms-flex:0 1 auto;flex:0 1 auto;text-overflow:ellipsis;overflow:hidden\n}\n.user-info .user-meta{margin-bottom:.15em;display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;font-size:14px;line-height:22px;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.user-info .user-meta .following{-ms-flex:1 0 auto;flex:1 0 auto;margin:0;margin-bottom:.25em;text-align:left\n}\n.user-info .user-meta .highlighter{-ms-flex:0 1 auto;flex:0 1 auto;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-.5em;-ms-flex-item-align:start;align-self:start\n}\n.user-info .user-meta .highlighter .userHighlightCl{padding:2px 10px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightSel,.user-info .user-meta .highlighter .userHighlightSel.select{padding-top:0;padding-bottom:0;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightSel.select i{line-height:22px\n}\n.user-info .user-meta .highlighter .userHighlightText{width:70px;-ms-flex:1 0 auto;flex:1 0 auto\n}\n.user-info .user-meta .highlighter .userHighlightCl,.user-info .user-meta .highlighter .userHighlightText,.user-info .user-meta .highlighter .userHighlightSel,.user-info .user-meta .highlighter .userHighlightSel.select{height:22px;vertical-align:top;margin-right:.5em;margin-bottom:.25em\n}\n.user-info .user-interactions{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-pack:justify;justify-content:space-between;margin-right:-.75em\n}\n.user-info .user-interactions div{-ms-flex:1 0 0px;flex:1 0 0;margin-right:.75em;margin-bottom:.6em;white-space:nowrap\n}\n.user-info .user-interactions .mute{max-width:220px;min-height:28px\n}\n.user-info .user-interactions .remote-follow{max-width:220px;min-height:28px\n}\n.user-info .user-interactions .follow{max-width:220px;min-height:28px\n}\n.user-info .user-interactions button{width:100%;height:100%;margin:0\n}\n.user-info .user-interactions .remote-button{height:28px !important;width:92%\n}\n.user-info .user-interactions .pressed{border-bottom-color:rgba(255,255,255,0.2);border-top-color:rgba(0,0,0,0.2)\n}\n.user-counts{display:-ms-flexbox;display:flex;line-height:16px;padding:.5em 1.5em 0em 1.5em;text-align:center;-ms-flex-pack:justify;justify-content:space-between;color:#b9b9ba;color:var(--lightText, #b9b9ba);-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.user-count{-ms-flex:1 0 auto;flex:1 0 auto;padding:.5em 0 .5em 0;margin:0 .5em\n}\n.user-count h5{font-size:1em;font-weight:bolder;margin:0 0 0.25em\n}\n.user-count a{text-decoration:none\n}\n.dailyAvg{margin-left:1em;font-size:0.7em;color:#CCC\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card_content/user_card_content.vue","\n.spacer{height:1em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/status_or_conversation/status_or_conversation.vue","\n.name-and-screen-name{margin-left:0.7em;margin-top:0.0em;text-align:left;width:100%\n}\n.name-and-screen-name .user-name img{object-fit:contain;height:16px;width:16px;vertical-align:middle\n}\n.follows-you{margin-left:2em;float:right\n}\n.card{display:-ms-flexbox;display:flex;-ms-flex:1 0;flex:1 0;padding-top:0.6em;padding-right:1em;padding-bottom:0.6em;padding-left:1em;border-bottom:1px solid;margin:0;border-bottom-color:#222;border-bottom-color:var(--border, #222)\n}\n.card .avatar{margin-top:0.2em;width:32px;height:32px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.usercard{width:-webkit-fill-available;width:-moz-available;width:fill-available;margin:0.2em 0 0.7em 0;border-radius:10px;border-radius:var(--panelRadius, 10px);border-style:solid;border-color:#222;border-color:var(--border, #222);border-width:1px;overflow:hidden\n}\n.usercard .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.usercard p{margin-bottom:0\n}\n.approval button{width:100%;margin-bottom:0.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card/user_card.vue","\n.user-profile{-ms-flex:2;flex:2;-ms-flex-preferred-size:500px;flex-basis:500px\n}\n.user-profile .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.user-profile .userlist-placeholder{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:middle;align-items:middle;padding:2em\n}\n.user-profile .timeline-heading{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center\n}\n.user-profile .timeline-heading .loadmore-button,.user-profile .timeline-heading .alert{-ms-flex:1;flex:1\n}\n.user-profile .timeline-heading .loadmore-button{height:28px;margin:10px .6em\n}\n.user-profile .timeline-heading .title,.user-profile .timeline-heading .loadmore-text{display:none\n}\n.user-profile-placeholder .panel-body{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:middle;align-items:middle;padding:7em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_profile/user_profile.vue","\n.setting-item{border-bottom:2px solid var(--fg, #182230);margin:1em 1em 1.4em;padding-bottom:1.4em\n}\n.setting-item>div{margin-bottom:.5em\n}\n.setting-item>div:last-child{margin-bottom:0\n}\n.setting-item:last-child{border-bottom:none;padding-bottom:0;margin-bottom:1em\n}\n.setting-item select{min-width:10em\n}\n.setting-item textarea{width:100%;height:100px\n}\n.setting-item .unavailable,.setting-item .unavailable i{color:var(--cRed, red);color:red\n}\n.setting-item .old-avatar{width:128px;border-radius:4px;border-radius:var(--avatarRadius, 4px)\n}\n.setting-item .new-avatar{object-fit:cover;width:128px;height:128px;border-radius:4px;border-radius:var(--avatarRadius, 4px)\n}\n.setting-item .btn{min-height:28px;min-width:10em;padding:0 2em\n}\n.select-multiple{display:-ms-flexbox;display:flex\n}\n.select-multiple .option-list{margin:0;padding-left:.5em\n}\n.setting-list,.option-list{list-style-type:none;padding-left:2em\n}\n.setting-list li,.option-list li{margin-bottom:0.5em\n}\n.setting-list .suboptions,.option-list .suboptions{margin-top:0.3em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/settings/settings.vue","@import '../../_variables.scss';\n\n.tab-switcher {\n .contents {\n .hidden {\n display: none;\n }\n }\n .tabs {\n display: flex;\n position: relative;\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n box-sizing: border-box;\n\n &::after, &::before {\n display: block;\n content: '';\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: $fallback--border;\n border-bottom-color: var(--border, $fallback--border);\n }\n\n .tab-wrapper {\n height: 28px;\n position: relative;\n display: flex;\n flex: 0 0 auto;\n\n .tab {\n width: 100%;\n min-width: 1px;\n position: relative;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding: 6px 1em;\n padding-bottom: 99px;\n margin-bottom: 6px - 99px;\n white-space: nowrap;\n\n &:not(.active) {\n z-index: 4;\n\n &:hover {\n z-index: 6;\n }\n }\n\n &.active {\n background: transparent;\n z-index: 5;\n }\n }\n\n &:not(.active) {\n &::after {\n content: '';\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 7;\n border-bottom: 1px solid;\n border-bottom-color: $fallback--border;\n border-bottom-color: var(--border, $fallback--border);\n }\n }\n }\n\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/tab_switcher/src/components/tab_switcher/tab_switcher.scss","\n.style-switcher .preset-switcher{margin-right:1em\n}\n.style-switcher .style-control{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline;margin-bottom:5px\n}\n.style-switcher .style-control .label{-ms-flex:1;flex:1\n}\n.style-switcher .style-control.disabled input:not(.exclude-disabled),.style-switcher .style-control.disabled select:not(.exclude-disabled){opacity:.5\n}\n.style-switcher .style-control input,.style-switcher .style-control select{min-width:3em;margin:0;-ms-flex:0;flex:0\n}\n.style-switcher .style-control input[type=color],.style-switcher .style-control select[type=color]{padding:1px;cursor:pointer;height:29px;min-width:2em;border:none;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.style-switcher .style-control input[type=number],.style-switcher .style-control select[type=number]{min-width:5em\n}\n.style-switcher .style-control input[type=range],.style-switcher .style-control select[type=range]{-ms-flex:1;flex:1;min-width:3em\n}\n.style-switcher .style-control input[type=checkbox]+label,.style-switcher .style-control select[type=checkbox]+label{margin:6px 0\n}\n.style-switcher .style-control input:not([type=number]):not([type=text]),.style-switcher .style-control select:not([type=number]):not([type=text]){-ms-flex-item-align:start;align-self:flex-start\n}\n.style-switcher .tab-switcher{margin:0 -1em\n}\n.style-switcher .reset-container{-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.style-switcher .fonts-container,.style-switcher .reset-container,.style-switcher .apply-container,.style-switcher .radius-container,.style-switcher .color-container{display:-ms-flexbox;display:flex\n}\n.style-switcher .fonts-container,.style-switcher .radius-container{-ms-flex-direction:column;flex-direction:column\n}\n.style-switcher .color-container{-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:justify;justify-content:space-between\n}\n.style-switcher .color-container>h4{width:99%\n}\n.style-switcher .fonts-container,.style-switcher .color-container,.style-switcher .shadow-container,.style-switcher .radius-container,.style-switcher .presets-container{margin:1em 1em 0\n}\n.style-switcher .tab-header{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:baseline;align-items:baseline;width:100%;min-height:30px;margin-bottom:1em\n}\n.style-switcher .tab-header .btn{min-width:1px;-ms-flex:0 auto;flex:0 auto;padding:0 1em\n}\n.style-switcher .tab-header p{-ms-flex:1;flex:1;margin:0;margin-right:.5em\n}\n.style-switcher .shadow-selector .override{-ms-flex:1;flex:1;margin-left:.5em\n}\n.style-switcher .shadow-selector .select-container{margin-top:-4px;margin-bottom:-3px\n}\n.style-switcher .save-load,.style-switcher .save-load-options{display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:baseline;align-items:baseline;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.style-switcher .save-load .presets,.style-switcher .save-load .import-export,.style-switcher .save-load-options .presets,.style-switcher .save-load-options .import-export{margin-bottom:.5em\n}\n.style-switcher .save-load .import-export,.style-switcher .save-load-options .import-export{display:-ms-flexbox;display:flex\n}\n.style-switcher .save-load .override,.style-switcher .save-load-options .override{margin-left:.5em\n}\n.style-switcher .save-load-options{-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:.5em;-ms-flex-pack:center;justify-content:center\n}\n.style-switcher .save-load-options .keep-option{margin:0 .5em .5em;min-width:25%\n}\n.style-switcher .preview-container{border-top:1px dashed;border-bottom:1px dashed;border-color:#222;border-color:var(--border, #222);margin:1em -1em 0;padding:1em;background:var(--body-background-image);background-size:cover;background-position:50% 50%\n}\n.style-switcher .preview-container .dummy .post{font-family:var(--postFont);display:-ms-flexbox;display:flex\n}\n.style-switcher .preview-container .dummy .post .content{-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .post .content h4{margin-bottom:.25em\n}\n.style-switcher .preview-container .dummy .post .content .icons{margin-top:.5em;display:-ms-flexbox;display:flex\n}\n.style-switcher .preview-container .dummy .post .content .icons i{margin-right:1em\n}\n.style-switcher .preview-container .dummy .after-post{margin-top:1em;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center\n}\n.style-switcher .preview-container .dummy .avatar,.style-switcher .preview-container .dummy .avatar-alt{background:linear-gradient(135deg, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%);color:black;font-family:sans-serif;text-align:center;margin-right:1em\n}\n.style-switcher .preview-container .dummy .avatar-alt{-ms-flex:0 auto;flex:0 auto;margin-left:28px;font-size:12px;min-width:20px;min-height:20px;line-height:20px;border-radius:10px;border-radius:var(--avatarAltRadius, 10px)\n}\n.style-switcher .preview-container .dummy .avatar{-ms-flex:0 auto;flex:0 auto;width:48px;height:48px;font-size:14px;line-height:48px\n}\n.style-switcher .preview-container .dummy .actions{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline\n}\n.style-switcher .preview-container .dummy .actions .checkbox{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:baseline;align-items:baseline;margin-right:1em;-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .separator{margin:1em;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222)\n}\n.style-switcher .preview-container .dummy .panel-heading .badge,.style-switcher .preview-container .dummy .panel-heading .alert,.style-switcher .preview-container .dummy .panel-heading .btn,.style-switcher .preview-container .dummy .panel-heading .faint{margin-left:1em;white-space:nowrap\n}\n.style-switcher .preview-container .dummy .panel-heading .faint{text-overflow:ellipsis;min-width:2em;overflow-x:hidden\n}\n.style-switcher .preview-container .dummy .panel-heading .flex-spacer{-ms-flex:1;flex:1\n}\n.style-switcher .preview-container .dummy .btn{margin-left:0;padding:0 1em;min-width:3em;min-height:30px\n}\n.style-switcher .apply-container{-ms-flex-pack:center;justify-content:center\n}\n.style-switcher .radius-item,.style-switcher .color-item{min-width:20em;margin:5px 6px 0 0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex:1 1 0px;flex:1 1 0\n}\n.style-switcher .radius-item.wide,.style-switcher .color-item.wide{min-width:60%\n}\n.style-switcher .radius-item:not(.wide):nth-child(2n+1),.style-switcher .color-item:not(.wide):nth-child(2n+1){margin-right:7px\n}\n.style-switcher .radius-item .color,.style-switcher .radius-item .opacity,.style-switcher .color-item .color,.style-switcher .color-item .opacity{display:-ms-flexbox;display:flex;-ms-flex-align:baseline;align-items:baseline\n}\n.style-switcher .radius-item{-ms-flex-preferred-size:auto;flex-basis:auto\n}\n.style-switcher .theme-radius-rn,.style-switcher .theme-color-cl{border:0;box-shadow:none;background:transparent;color:var(--faint, rgba(185,185,186,0.5));-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.style-switcher .theme-color-cl,.style-switcher .theme-radius-in,.style-switcher .theme-color-in{margin-left:4px\n}\n.style-switcher .theme-radius-in{min-width:1em\n}\n.style-switcher .theme-radius-in{max-width:7em;-ms-flex:1;flex:1\n}\n.style-switcher .theme-radius-lb{max-width:50em\n}\n.style-switcher .theme-preview-content{padding:20px\n}\n.style-switcher .btn{margin-left:.25em;margin-right:.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/style_switcher/style_switcher.scss","\n.color-control input.text-input{max-width:7em;-ms-flex:1;flex:1\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/color_input/color_input.vue","\n.shadow-control{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center;margin-bottom:1em\n}\n.shadow-control .shadow-preview-container,.shadow-control .shadow-tweak{margin:5px 6px 0 0\n}\n.shadow-control .shadow-preview-container{-ms-flex:0;flex:0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.shadow-control .shadow-preview-container input[type=number]{width:5em;min-width:2em\n}\n.shadow-control .shadow-preview-container .x-shift-control,.shadow-control .shadow-preview-container .y-shift-control{display:-ms-flexbox;display:flex;-ms-flex:0;flex:0\n}\n.shadow-control .shadow-preview-container .x-shift-control[disabled=disabled] *,.shadow-control .shadow-preview-container .y-shift-control[disabled=disabled] *{opacity:.5\n}\n.shadow-control .shadow-preview-container .x-shift-control{-ms-flex-align:start;align-items:flex-start\n}\n.shadow-control .shadow-preview-container .x-shift-control .wrap,.shadow-control .shadow-preview-container input[type=range]{margin:0;width:15em;height:2em\n}\n.shadow-control .shadow-preview-container .y-shift-control{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:end;align-items:flex-end\n}\n.shadow-control .shadow-preview-container .y-shift-control .wrap{width:2em;height:15em\n}\n.shadow-control .shadow-preview-container .y-shift-control input[type=range]{transform-origin:1em 1em;transform:rotate(90deg)\n}\n.shadow-control .shadow-preview-container .preview-window{-ms-flex:1;flex:1;background-color:#999999;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;background-image:linear-gradient(45deg, #666 25%, transparent 25%),linear-gradient(-45deg, #666 25%, transparent 25%),linear-gradient(45deg, transparent 75%, #666 75%),linear-gradient(-45deg, transparent 75%, #666 75%);background-size:20px 20px;background-position:0 0, 0 10px, 10px -10px, -10px 0;border-radius:4px;border-radius:var(--inputRadius, 4px)\n}\n.shadow-control .shadow-preview-container .preview-window .preview-block{width:33%;height:33%;background-color:#121a24;background-color:var(--bg, #121a24);border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.shadow-control .shadow-tweak{-ms-flex:1;flex:1;min-width:280px\n}\n.shadow-control .shadow-tweak .id-control{-ms-flex-align:stretch;align-items:stretch\n}\n.shadow-control .shadow-tweak .id-control .select,.shadow-control .shadow-tweak .id-control .btn{min-width:1px;margin-right:5px\n}\n.shadow-control .shadow-tweak .id-control .btn{padding:0 .4em;margin:0 .1em\n}\n.shadow-control .shadow-tweak .id-control .select{-ms-flex:1;flex:1\n}\n.shadow-control .shadow-tweak .id-control .select select{-ms-flex-item-align:initial;-ms-grid-row-align:initial;align-self:initial\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/shadow_control/shadow_control.vue","\n.font-control input.custom-font{min-width:10em\n}\n.font-control.custom .select{border-top-right-radius:0;border-bottom-right-radius:0\n}\n.font-control.custom .custom-font{border-top-left-radius:0;border-bottom-left-radius:0\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/font_control/font_control.vue","\n.contrast-ratio{display:-ms-flexbox;display:flex;-ms-flex-pack:end;justify-content:flex-end;margin-top:-4px;margin-bottom:5px\n}\n.contrast-ratio .label{margin-right:1em\n}\n.contrast-ratio .rating{display:inline-block;text-align:center\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/contrast_ratio/contrast_ratio.vue","\n.import-export-container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:baseline;align-items:baseline;-ms-flex-pack:center;justify-content:center\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/export_import/export_import.vue","\n.registration-form{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:0.6em\n}\n.registration-form .container{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row\n}\n.registration-form .terms-of-service{-ms-flex:0 1 50%;flex:0 1 50%;margin:0.8em\n}\n.registration-form .text-fields{margin-top:0.6em;-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column\n}\n.registration-form .form-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0.3em 0.0em 0.3em;line-height:24px;margin-bottom:1em\n}\n@keyframes shakeError{\n0%{transform:translateX(0)\n}\n15%{transform:translateX(0.375rem)\n}\n30%{transform:translateX(-0.375rem)\n}\n45%{transform:translateX(0.375rem)\n}\n60%{transform:translateX(-0.375rem)\n}\n75%{transform:translateX(0.375rem)\n}\n90%{transform:translateX(-0.375rem)\n}\n100%{transform:translateX(0)\n}\n}\n.registration-form .form-group--error{animation-name:shakeError;animation-duration:.6s;animation-timing-function:ease-in-out\n}\n.registration-form .form-group--error .form--label{color:#f04124;color:var(--cRed, #f04124)\n}\n.registration-form .form-error{margin-top:-0.7em;text-align:left\n}\n.registration-form .form-error span{font-size:12px\n}\n.registration-form .form-error ul{list-style:none;padding:0 0 0 5px;margin-top:0\n}\n.registration-form .form-error ul li::before{content:\"• \"\n}\n.registration-form form textarea{line-height:16px;resize:vertical\n}\n.registration-form .captcha{max-width:350px;margin-bottom:0.4em\n}\n.registration-form .btn{margin-top:0.6em;height:28px\n}\n.registration-form .error{text-align:center\n}\n@media all and (max-width: 959px){\n.registration-form .container{-ms-flex-direction:column-reverse;flex-direction:column-reverse\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/registration/registration.vue","\n.profile-edit .bio{margin:0\n}\n.profile-edit input[type=file]{padding:5px;height:auto\n}\n.profile-edit .banner{max-width:400px\n}\n.profile-edit .uploading{font-size:1.5em;margin:0.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_settings/user_settings.vue","\n.user-search-input-container{margin:0.5em;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center\n}\n.user-search-input-container .search-button{margin-left:0.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_search/user_search.vue","\n.notifications{padding-bottom:15em\n}\n.notifications .loadmore-error{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.notifications .notification{position:relative\n}\n.notifications .notification .notification-overlay{position:absolute;top:0;right:0;left:0;bottom:0;pointer-events:none\n}\n.notifications .notification.unseen .notification-overlay{background-image:linear-gradient(135deg, var(--badgeNotification, red) 4px, transparent 10px)\n}\n.notification{box-sizing:border-box;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222)\n}\n.notification .avatar-compact{width:32px;height:32px;box-shadow:var(--avatarStatusShadow);border-radius:10px;border-radius:var(--avatarAltRadius, 10px);overflow:hidden;line-height:0\n}\n.notification .avatar-compact.better-shadow{box-shadow:var(--avatarStatusShadowInset);filter:var(--avatarStatusShadowFilter)\n}\n.notification .avatar-compact.animated::before{display:none\n}\n.notification:hover .animated.avatar-compact canvas{display:none\n}\n.notification:hover .animated.avatar-compact img{visibility:visible\n}\n.notification .notification-usercard{margin:0\n}\n.notification .non-mention{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding:0.6em;min-width:0\n}\n.notification .non-mention .avatar-container{width:32px;height:32px\n}\n.notification .non-mention .status-el{padding:0\n}\n.notification .non-mention .status-el .status{padding:0.25em 0;color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n.notification .non-mention .status-el .status a{color:var(--faintLink)\n}\n.notification .non-mention .status-el .media-body{margin:0\n}\n.notification .follow-text{padding:0.5em 0\n}\n.notification .status-el{-ms-flex:1;flex:1\n}\n.notification time{white-space:nowrap\n}\n.notification .notification-right{-ms-flex:1;flex:1;padding-left:0.8em;min-width:0\n}\n.notification .notification-details{min-width:0px;word-wrap:break-word;line-height:18px;position:relative;overflow:hidden;width:100%;-ms-flex:1 1 0px;flex:1 1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap\n}\n.notification .notification-details .name-and-action{-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis\n}\n.notification .notification-details .username{font-weight:bolder;max-width:100%;text-overflow:ellipsis;white-space:nowrap\n}\n.notification .notification-details .username img{width:14px;height:14px;vertical-align:middle;object-fit:contain\n}\n.notification .notification-details .timeago{float:right;font-size:12px\n}\n.notification .notification-details .icon-retweet.lit{color:#0fa00f;color:var(--cGreen, #0fa00f)\n}\n.notification .notification-details .icon-user-plus.lit{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.notification .notification-details .icon-reply.lit{color:#0095ff;color:var(--cBlue, #0095ff)\n}\n.notification .notification-details .icon-star.lit{color:orange;color:orange;color:var(--cOrange, orange)\n}\n.notification .notification-details .status-content{margin:0;max-height:300px\n}\n.notification .notification-details h1{word-break:break-all;margin:0 0 0.3em;padding:0;font-size:1em;line-height:20px\n}\n.notification .notification-details h1 small{font-weight:lighter\n}\n.notification .notification-details p{margin:0;margin-top:0;margin-bottom:0.3em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/notifications/notifications.scss","\n.user-panel .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_panel/user_panel.vue","\n.login-form .btn{min-height:28px;width:10em\n}\n.login-form .error{text-align:center\n}\n.login-form .register{-ms-flex:1 1;flex:1 1\n}\n.login-form .login-bottom{margin-top:1.0em;display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/login_form/login_form.vue","\n.floating-chat{position:fixed;right:0px;bottom:0px;z-index:1000;max-width:25em\n}\n.chat-heading{cursor:pointer\n}\n.chat-heading .icon-comment-empty{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\n.chat-window{overflow-y:auto;overflow-x:hidden;max-height:20em\n}\n.chat-window-container{height:100%\n}\n.chat-message{display:-ms-flexbox;display:flex;padding:0.2em 0.5em\n}\n.chat-avatar img{height:24px;width:24px;border-radius:4px;border-radius:var(--avatarRadius, 4px);margin-right:0.5em;margin-top:0.25em\n}\n.chat-input{display:-ms-flexbox;display:flex\n}\n.chat-input textarea{-ms-flex:1;flex:1;margin:0.6em;min-height:3.5em;resize:none\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/chat_panel/chat_panel.vue","\n#app{background-size:cover;background-attachment:fixed;background-repeat:no-repeat;background-position:0 50px;min-height:100vh;max-width:100%;overflow:hidden\n}\ni{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none\n}\nh4{margin:0\n}\n#content{box-sizing:border-box;padding-top:60px;margin:auto;min-height:100vh;max-width:980px;background-color:rgba(0,0,0,0.15);-ms-flex-line-pack:start;align-content:flex-start\n}\n.text-center{text-align:center\n}\nbody{font-family:sans-serif;font-family:var(--interfaceFont, sans-serif);font-size:14px;margin:0;color:#b9b9ba;color:var(--text, #b9b9ba);max-width:100vw;overflow-x:hidden\n}\na{text-decoration:none;color:#d8a070;color:var(--link, #d8a070)\n}\nbutton{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#b9b9ba;color:var(--btnText, #b9b9ba);background-color:#182230;background-color:var(--btn, #182230);border:none;border-radius:4px;border-radius:var(--btnRadius, 4px);cursor:pointer;box-shadow:0px 0px 2px 0px #000,0px 1px 0px 0px rgba(255,255,255,0.2) inset,0px -1px 0px 0px rgba(0,0,0,0.2) inset;box-shadow:var(--buttonShadow);font-size:14px;font-family:sans-serif;font-family:var(--interfaceFont, sans-serif)\n}\nbutton i[class*=icon-]{color:#b9b9ba;color:var(--btnText, #b9b9ba)\n}\nbutton::-moz-focus-inner{border:none\n}\nbutton:hover{box-shadow:0px 0px 4px rgba(255,255,255,0.3);box-shadow:var(--buttonHoverShadow)\n}\nbutton:active{box-shadow:0px 0px 4px 0px rgba(255,255,255,0.3),0px 1px 0px 0px rgba(0,0,0,0.2) inset,0px -1px 0px 0px rgba(255,255,255,0.2) inset;box-shadow:var(--buttonPressedShadow)\n}\nbutton:disabled{cursor:not-allowed;opacity:0.5\n}\nbutton.pressed{color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5));background-color:#121a24;background-color:var(--bg, #121a24)\n}\nlabel.select{padding:0\n}\ninput,textarea,.select{border:none;border-radius:4px;border-radius:var(--inputRadius, 4px);box-shadow:0px 1px 0px 0px rgba(0,0,0,0.2) inset,0px -1px 0px 0px rgba(255,255,255,0.2) inset,0px 0px 2px 0px #000 inset;box-shadow:var(--inputShadow);background-color:#182230;background-color:var(--input, #182230);color:#b9b9ba;color:var(--inputText, #b9b9ba);font-family:sans-serif;font-family:var(--inputFont, sans-serif);font-size:14px;padding:8px .5em;box-sizing:border-box;display:inline-block;position:relative;height:28px;line-height:16px;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none\n}\ninput:disabled,input[disabled=disabled],textarea:disabled,textarea[disabled=disabled],.select:disabled,.select[disabled=disabled]{cursor:not-allowed;opacity:0.5\n}\ninput .icon-down-open,textarea .icon-down-open,.select .icon-down-open{position:absolute;top:0;bottom:0;right:5px;height:100%;color:#b9b9ba;color:var(--text, #b9b9ba);line-height:28px;z-index:0;pointer-events:none\n}\ninput select,textarea select,.select select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:#b9b9ba;color:var(--text, #b9b9ba);margin:0;padding:0 2em 0 .2em;font-family:sans-serif;font-family:var(--inputFont, sans-serif);font-size:14px;width:100%;z-index:1;height:28px;line-height:16px\n}\ninput[type=range],textarea[type=range],.select[type=range]{background:none;border:none;margin:0;box-shadow:none;-ms-flex:1;flex:1\n}\ninput[type=radio],input[type=checkbox],textarea[type=radio],textarea[type=checkbox],.select[type=radio],.select[type=checkbox]{display:none\n}\ninput[type=radio]:checked+label::before,input[type=checkbox]:checked+label::before,textarea[type=radio]:checked+label::before,textarea[type=checkbox]:checked+label::before,.select[type=radio]:checked+label::before,.select[type=checkbox]:checked+label::before{color:#b9b9ba;color:var(--text, #b9b9ba)\n}\ninput[type=radio]:disabled,input[type=radio]:disabled+label,input[type=radio]:disabled+label::before,input[type=checkbox]:disabled,input[type=checkbox]:disabled+label,input[type=checkbox]:disabled+label::before,textarea[type=radio]:disabled,textarea[type=radio]:disabled+label,textarea[type=radio]:disabled+label::before,textarea[type=checkbox]:disabled,textarea[type=checkbox]:disabled+label,textarea[type=checkbox]:disabled+label::before,.select[type=radio]:disabled,.select[type=radio]:disabled+label,.select[type=radio]:disabled+label::before,.select[type=checkbox]:disabled,.select[type=checkbox]:disabled+label,.select[type=checkbox]:disabled+label::before{opacity:.5\n}\ninput[type=radio]+label::before,input[type=checkbox]+label::before,textarea[type=radio]+label::before,textarea[type=checkbox]+label::before,.select[type=radio]+label::before,.select[type=checkbox]+label::before{display:inline-block;content:'✔';transition:color 200ms;width:1.1em;height:1.1em;border-radius:2px;border-radius:var(--checkboxRadius, 2px);box-shadow:0px 0px 2px black inset;box-shadow:var(--inputShadow);margin-right:.5em;background-color:#182230;background-color:var(--input, #182230);vertical-align:top;text-align:center;line-height:1.1em;font-size:1.1em;box-sizing:border-box;color:transparent;overflow:hidden;box-sizing:border-box\n}\noption{color:#b9b9ba;color:var(--text, #b9b9ba);background-color:#121a24;background-color:var(--bg, #121a24)\n}\ni[class*=icon-]{color:#666;color:var(--icon, #666)\n}\n.container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0 10px 0 10px\n}\n.item{-ms-flex:1;flex:1;line-height:50px;height:50px;overflow:hidden;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.item .nav-icon{margin-left:0.4em\n}\n.item.right{-ms-flex-pack:end;justify-content:flex-end\n}\n.auto-size{-ms-flex:1;flex:1\n}\n.nav-bar{padding:0;width:100%;-ms-flex-align:center;align-items:center;position:fixed;height:50px\n}\n.nav-bar .logo{display:-ms-flexbox;display:flex;position:absolute;top:0;bottom:0;left:0;right:0;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:center;justify-content:center;-ms-flex:0 0 auto;flex:0 0 auto;z-index:-1;transition:opacity;transition-timing-function:ease-out;transition-duration:100ms\n}\n.nav-bar .logo .mask{-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;mask-size:contain;background-color:#182230;background-color:var(--topBarText, #182230);position:absolute;top:0;bottom:0;left:0;right:0\n}\n.nav-bar .logo img{height:100%;object-fit:contain;display:block;-ms-flex:0;flex:0\n}\n.nav-bar .inner-nav{margin:auto;box-sizing:border-box;padding-left:10px;padding-right:10px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-preferred-size:970px;flex-basis:970px;height:50px\n}\n.nav-bar .inner-nav a,.nav-bar .inner-nav a i{color:#d8a070;color:var(--topBarLink, #d8a070)\n}\nmain-router{-ms-flex:1;flex:1\n}\n.status.compact{color:rgba(0,0,0,0.42);font-weight:300\n}\n.status.compact p{margin:0;font-size:0.8em\n}\n.panel{display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;margin:0.5em;background-color:#121a24;background-color:var(--bg, #121a24)\n}\n.panel::after,.panel{border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.panel::after{content:'';position:absolute;top:0;bottom:0;left:0;right:0;pointer-events:none;box-shadow:1px 1px 4px rgba(0,0,0,0.6);box-shadow:var(--panelShadow)\n}\n.panel-body:empty::before{content:\"¯\\\\_(ツ)_/¯\";display:block;margin:1em;text-align:center\n}\n.panel-heading{display:-ms-flexbox;display:flex;border-radius:10px 10px 0 0;border-radius:var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0;background-size:cover;padding:.6em .6em;text-align:left;line-height:28px;color:var(--panelText);background-color:#182230;background-color:var(--panel, #182230);-ms-flex-align:baseline;align-items:baseline;box-shadow:var(--panelHeaderShadow)\n}\n.panel-heading .title{-ms-flex:1 0 auto;flex:1 0 auto;font-size:1.3em\n}\n.panel-heading .faint{background-color:transparent;color:rgba(185,185,186,0.5);color:var(--panelFaint, rgba(185,185,186,0.5))\n}\n.panel-heading .alert{white-space:nowrap;text-overflow:ellipsis;overflow-x:hidden\n}\n.panel-heading button{-ms-flex-negative:0;flex-shrink:0\n}\n.panel-heading button,.panel-heading .alert{line-height:21px;min-height:0;box-sizing:border-box;margin:0;margin-left:.25em;min-width:1px;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch\n}\n.panel-heading a{color:#d8a070;color:var(--panelLink, #d8a070)\n}\n.panel-heading.stub{border-radius:10px;border-radius:var(--panelRadius, 10px)\n}\n.panel-footer{border-radius:0 0 10px 10px;border-radius:0 0 var(--panelRadius, 10px) var(--panelRadius, 10px)\n}\n.panel-footer a{color:#d8a070;color:var(--panelLink, #d8a070)\n}\n.panel-body>p{line-height:18px;padding:1em;margin:0\n}\n.container>*{min-width:0px\n}\n.fa{color:grey\n}\nnav{z-index:1000;color:var(--topBarText);background-color:#182230;background-color:var(--topBar, #182230);color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5));box-shadow:0px 0px 4px rgba(0,0,0,0.6);box-shadow:var(--topBarShadow)\n}\nnav .back-button{display:block;max-width:99px;transition-property:opacity, max-width;transition-duration:300ms;transition-timing-function:ease-out\n}\nnav .back-button i{margin:0 1em\n}\nnav .back-button.hidden{opacity:0;max-width:5px\n}\n.menu-button{display:none;position:relative\n}\n.alert-dot{border-radius:100%;height:8px;width:8px;position:absolute;left:calc(50% - 4px);top:calc(50% - 4px);margin-left:6px;margin-top:-6px;background-color:red;background-color:var(--badgeNotification, red)\n}\n.fade-enter-active,.fade-leave-active{transition:opacity .2s\n}\n.fade-enter,.fade-leave-active{opacity:0\n}\n.main{-ms-flex-preferred-size:60%;flex-basis:60%;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:1;flex-shrink:1\n}\n.sidebar-bounds{-ms-flex:0;flex:0;-ms-flex-preferred-size:35%;flex-basis:35%\n}\n.sidebar-flexer{-ms-flex:1;flex:1;-ms-flex-preferred-size:345px;flex-basis:345px;width:365px\n}\n.mobile-shown{display:none\n}\n.panel-switcher{display:none;width:100%;height:46px\n}\n.panel-switcher button{display:block;-ms-flex:1;flex:1;max-height:32px;margin:0.5em;padding:0.5em\n}\n@media all and (min-width: 960px){\nbody{overflow-y:scroll\n}\nnav .back-button{display:none\n}\n.sidebar-bounds{overflow:hidden;max-height:100vh;width:345px;position:fixed;margin-top:-10px\n}\n.sidebar-bounds .sidebar-scroller{height:96vh;width:365px;padding-top:10px;padding-right:50px;overflow-x:hidden;overflow-y:scroll\n}\n.sidebar-bounds .sidebar{width:345px\n}\n.sidebar-flexer{max-height:96vh;-ms-flex-negative:0;flex-shrink:0;-ms-flex-positive:0;flex-grow:0\n}\n}\n.badge{display:inline-block;border-radius:99px;min-width:22px;max-width:22px;min-height:22px;max-height:22px;font-size:15px;line-height:22px;text-align:center;vertical-align:middle;white-space:nowrap;padding:0\n}\n.badge.badge-notification{background-color:red;background-color:var(--badgeNotification, red);color:white;color:var(--badgeNotificationText, #fff)\n}\n.alert{margin:0.35em;padding:0.25em;border-radius:5px;border-radius:var(--tooltipRadius, 5px);min-height:28px;line-height:28px\n}\n.alert.error{background-color:rgba(211,16,20,0.5);background-color:var(--alertError, rgba(211,16,20,0.5));color:#b9b9ba;color:var(--alertErrorText, #b9b9ba)\n}\n.panel-heading .alert.error{color:#b9b9ba;color:var(--alertErrorPanelText, #b9b9ba)\n}\n.faint{color:rgba(185,185,186,0.5);color:var(--faint, rgba(185,185,186,0.5))\n}\n@media all and (min-width: 959px){\n.logo{opacity:1 !important\n}\n}\n.item.right{text-align:right\n}\n.visibility-tray{font-size:1.2em;padding:3px;cursor:pointer\n}\n.visibility-tray .selected{color:#b9b9ba;color:var(--lightText, #b9b9ba)\n}\n.visibility-tray .text-format{float:right\n}\n.visibility-tray div{padding-top:5px\n}\n.visibility-notice{padding:.5em;border:1px solid rgba(185,185,186,0.5);border:1px solid var(--faint, rgba(185,185,186,0.5));border-radius:4px;border-radius:var(--inputRadius, 4px)\n}\n@media all and (max-width: 959px){\n.mobile-hidden{display:none\n}\n.panel-switcher{display:-ms-flexbox;display:flex\n}\n.container{padding:0\n}\n.panel{margin:0.5em 0 0.5em 0\n}\n.button-icon{font-size:1.2em\n}\n.status .status-actions div{max-width:4em\n}\n.menu-button{display:block;margin-right:0.8em\n}\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/App.scss","\n.nav-panel .panel{overflow:hidden\n}\n.nav-panel ul{list-style:none;margin:0;padding:0\n}\n.nav-panel li{border-bottom:1px solid;border-color:#222;border-color:var(--border, #222);padding:0\n}\n.nav-panel li:first-child a{border-top-right-radius:10px;border-top-right-radius:var(--panelRadius, 10px);border-top-left-radius:10px;border-top-left-radius:var(--panelRadius, 10px)\n}\n.nav-panel li:last-child a{border-bottom-right-radius:10px;border-bottom-right-radius:var(--panelRadius, 10px);border-bottom-left-radius:10px;border-bottom-left-radius:var(--panelRadius, 10px)\n}\n.nav-panel li:last-child{border:none\n}\n.nav-panel a{display:block;padding:0.8em 0.85em\n}\n.nav-panel a:hover{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.nav-panel a.router-link-active{font-weight:bolder;background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n.nav-panel a.router-link-active:hover{text-decoration:underline\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/nav_panel/nav_panel.vue","\n.user-finder-container{max-width:100%;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:baseline;align-items:baseline;vertical-align:baseline\n}\n.user-finder-container .user-finder-input,.user-finder-container .search-button{height:29px\n}\n.user-finder-container .user-finder-input{max-width:calc(100% - 30px - 30px - 20px)\n}\n.user-finder-container .search-button{margin-left:.5em;margin-right:.5em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_finder/user_finder.vue","\n.features-panel li{line-height:24px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/features_panel/features_panel.vue","\n.who-to-follow *{vertical-align:middle\n}\n.who-to-follow img{width:32px;height:32px\n}\n.who-to-follow p{line-height:40px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/who_to_follow_panel/who_to_follow_panel.vue","\n.side-drawer-container{position:fixed;z-index:1000;top:0;left:0;width:100%;height:100%;display:-ms-flexbox;display:flex;-ms-flex-align:stretch;align-items:stretch\n}\n.side-drawer-container-open{transition-delay:0.0s;transition-property:left\n}\n.side-drawer-container-closed{left:-100%;transition-delay:0.5s;transition-property:left\n}\n.side-drawer-click-outside{-ms-flex:1 1 100%;flex:1 1 100%\n}\n.side-drawer{overflow-x:hidden;transition:0.5s;transition-timing-function:cubic-bezier(0, 1, 0.5, 1);margin:0 0 0 -100px;padding:0 0 1em 100px;width:80%;max-width:20em;-ms-flex:0 0 80%;flex:0 0 80%;box-shadow:1px 1px 4px rgba(0,0,0,0.6);box-shadow:var(--panelShadow);background-color:#121a24;background-color:var(--bg, #121a24)\n}\n.side-drawer-click-outside-closed{-ms-flex:0 0 0px;flex:0 0 0\n}\n.side-drawer-closed{margin:0 0 0 calc(-100% - 100px)\n}\n.side-drawer-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch;display:-ms-flexbox;display:flex;min-height:7em;padding:0;margin:0\n}\n.side-drawer-heading .profile-panel-background{border-radius:0\n}\n.side-drawer-heading .profile-panel-background .panel-heading{background:transparent;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch\n}\n.side-drawer ul{list-style:none;margin:0;padding:0;border-bottom:1px solid;border-color:#222;border-color:var(--border, #222);margin:0.2em 0\n}\n.side-drawer ul:last-child{border:0\n}\n.side-drawer li{padding:0\n}\n.side-drawer li a{display:block;padding:0.5em 0.85em\n}\n.side-drawer li a:hover{background-color:#151e2a;background-color:var(--lightBg, #151e2a)\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/side_drawer/side_drawer.vue"],"sourceRoot":""}
\ No newline at end of file
diff --git a/priv/static/static/js/app.1c83eacd8eddeef56c69.js b/priv/static/static/js/app.1c83eacd8eddeef56c69.js
deleted file mode 100644
index f97b4009c..000000000
Binary files a/priv/static/static/js/app.1c83eacd8eddeef56c69.js and /dev/null differ
diff --git a/priv/static/static/js/app.1c83eacd8eddeef56c69.js.map b/priv/static/static/js/app.1c83eacd8eddeef56c69.js.map
deleted file mode 100644
index de84dba48..000000000
Binary files a/priv/static/static/js/app.1c83eacd8eddeef56c69.js.map and /dev/null differ
diff --git a/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js b/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js
new file mode 100644
index 000000000..5f30d29db
Binary files /dev/null and b/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js differ
diff --git a/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js.map b/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js.map
new file mode 100644
index 000000000..a69b2672a
Binary files /dev/null and b/priv/static/static/js/app.5ed04a69c4a6e8b1f455.js.map differ
diff --git a/priv/static/static/js/manifest.6802874440f1854a6844.js b/priv/static/static/js/manifest.6802874440f1854a6844.js
new file mode 100644
index 000000000..8f0fc2460
Binary files /dev/null and b/priv/static/static/js/manifest.6802874440f1854a6844.js differ
diff --git a/priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js.map b/priv/static/static/js/manifest.6802874440f1854a6844.js.map
similarity index 92%
rename from priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js.map
rename to priv/static/static/js/manifest.6802874440f1854a6844.js.map
index 0ca2e2044..f96d0a4a8 100644
Binary files a/priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js.map and b/priv/static/static/js/manifest.6802874440f1854a6844.js.map differ
diff --git a/priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js b/priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js
deleted file mode 100644
index e3a599272..000000000
Binary files a/priv/static/static/js/manifest.e833e1c75fbc9f2b69b4.js and /dev/null differ
diff --git a/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js b/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js
new file mode 100644
index 000000000..c0bd08259
Binary files /dev/null and b/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js differ
diff --git a/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js.map b/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js.map
new file mode 100644
index 000000000..b827959a7
Binary files /dev/null and b/priv/static/static/js/vendor.61fd03d8471aaadcf63c.js.map differ
diff --git a/priv/static/static/js/vendor.b6e63c523d95d763c254.js b/priv/static/static/js/vendor.b6e63c523d95d763c254.js
deleted file mode 100644
index dd90d4ebd..000000000
Binary files a/priv/static/static/js/vendor.b6e63c523d95d763c254.js and /dev/null differ
diff --git a/priv/static/static/js/vendor.b6e63c523d95d763c254.js.map b/priv/static/static/js/vendor.b6e63c523d95d763c254.js.map
deleted file mode 100644
index 3b5b37891..000000000
Binary files a/priv/static/static/js/vendor.b6e63c523d95d763c254.js.map and /dev/null differ
diff --git a/priv/static/static/logo.png b/priv/static/static/logo.png
index f83d923bb..7744b1acc 100644
Binary files a/priv/static/static/logo.png and b/priv/static/static/logo.png differ
diff --git a/priv/static/sw.js b/priv/static/sw.js
index f3c9a83a5..4e4b21a45 100644
Binary files a/priv/static/sw.js and b/priv/static/sw.js differ
diff --git a/test/activity_test.exs b/test/activity_test.exs
index 36c718869..ad889f544 100644
--- a/test/activity_test.exs
+++ b/test/activity_test.exs
@@ -16,7 +16,7 @@ test "returns an activity by it's AP id" do
test "returns activities by it's objects AP ids" do
activity = insert(:note_activity)
- [found_activity] = Activity.all_by_object_ap_id(activity.data["object"]["id"])
+ [found_activity] = Activity.get_all_create_by_object_ap_id(activity.data["object"]["id"])
assert activity == found_activity
end
@@ -24,7 +24,7 @@ test "returns activities by it's objects AP ids" do
test "returns the activity that created an object" do
activity = insert(:note_activity)
- found_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
+ found_activity = Activity.get_create_by_object_ap_id(activity.data["object"]["id"])
assert activity == found_activity
end
diff --git a/test/flake_id_test.exs b/test/flake_id_test.exs
new file mode 100644
index 000000000..8e969fd1c
--- /dev/null
+++ b/test/flake_id_test.exs
@@ -0,0 +1,41 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.FlakeIdTest do
+ use Pleroma.DataCase
+ import Kernel, except: [to_string: 1]
+ import Pleroma.FlakeId
+
+ describe "fake flakes (compatibility with older serial integers)" do
+ test "from_string/1" do
+ fake_flake = <<0::integer-size(64), 42::integer-size(64)>>
+ assert from_string("42") == fake_flake
+ end
+
+ test "zero or -1 is a null flake" do
+ fake_flake = <<0::integer-size(128)>>
+ assert from_string("0") == fake_flake
+ assert from_string("-1") == fake_flake
+ end
+
+ test "to_string/1" do
+ fake_flake = <<0::integer-size(64), 42::integer-size(64)>>
+ assert to_string(fake_flake) == "42"
+ end
+ end
+
+ test "ecto type behaviour" do
+ flake = <<0, 0, 1, 104, 80, 229, 2, 235, 140, 22, 69, 201, 53, 210, 0, 0>>
+ flake_s = "9eoozpwTul5mjSEDRI"
+
+ assert cast(flake) == {:ok, flake_s}
+ assert cast(flake_s) == {:ok, flake_s}
+
+ assert load(flake) == {:ok, flake_s}
+ assert load(flake_s) == {:ok, flake_s}
+
+ assert dump(flake_s) == {:ok, flake}
+ assert dump(flake) == {:ok, flake}
+ end
+end
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index bd8844458..2e717194b 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -124,7 +124,7 @@ test "turning urls into links" do
end
describe "add_user_links" do
- test "gives a replacement for user links" do
+ test "gives a replacement for user links, using local nicknames in user links text" do
text = "@gsimg According to @archa_eme_, that is @daggsy. Also hello @archaeme@archae.me"
gsimg = insert(:user, %{nickname: "gsimg"})
diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs
index 03aabf12c..2e385f5ad 100644
--- a/test/integration/mastodon_websocket_test.exs
+++ b/test/integration/mastodon_websocket_test.exs
@@ -66,13 +66,10 @@ test "receives well formatted events" do
assert json["payload"]
assert {:ok, json} = Jason.decode(json["payload"])
- # Note: we remove the "statuses_count" from this result as it changes in the meantime
-
view_json =
Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil)
|> Jason.encode!()
|> Jason.decode!()
- |> put_in(["account", "statuses_count"], 0)
assert json == view_json
end
diff --git a/test/user_test.exs b/test/user_test.exs
index cfccce8d1..092cfc5dc 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -775,14 +775,61 @@ test "User.delete() plugs any possible zombie objects" do
end
describe "User.search" do
- test "finds a user, ranking by similarity" do
- _user = insert(:user, %{name: "lain"})
- _user_two = insert(:user, %{name: "ean"})
- _user_three = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"})
- user_four = insert(:user, %{nickname: "lain@pleroma.soykaf.com"})
+ test "finds a user by full or partial nickname" do
+ user = insert(:user, %{nickname: "john"})
- assert user_four ==
- User.search("lain@ple") |> List.first() |> Map.put(:search_distance, nil)
+ Enum.each(["john", "jo", "j"], fn query ->
+ assert user == User.search(query) |> List.first() |> Map.put(:search_rank, nil)
+ end)
+ end
+
+ test "finds a user by full or partial name" do
+ user = insert(:user, %{name: "John Doe"})
+
+ Enum.each(["John Doe", "JOHN", "doe", "j d", "j", "d"], fn query ->
+ assert user == User.search(query) |> List.first() |> Map.put(:search_rank, nil)
+ end)
+ end
+
+ test "finds users, preferring nickname matches over name matches" do
+ u1 = insert(:user, %{name: "lain", nickname: "nick1"})
+ u2 = insert(:user, %{nickname: "lain", name: "nick1"})
+
+ assert [u2.id, u1.id] == Enum.map(User.search("lain"), & &1.id)
+ end
+
+ test "finds users, considering density of matched tokens" do
+ u1 = insert(:user, %{name: "Bar Bar plus Word Word"})
+ u2 = insert(:user, %{name: "Word Word Bar Bar Bar"})
+
+ assert [u2.id, u1.id] == Enum.map(User.search("bar word"), & &1.id)
+ end
+
+ test "finds users, ranking by similarity" do
+ u1 = insert(:user, %{name: "lain"})
+ _u2 = insert(:user, %{name: "ean"})
+ u3 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"})
+ u4 = insert(:user, %{nickname: "lain@pleroma.soykaf.com"})
+
+ assert [u4.id, u3.id, u1.id] == Enum.map(User.search("lain@ple"), & &1.id)
+ end
+
+ test "finds users, handling misspelled requests" do
+ u1 = insert(:user, %{name: "lain"})
+
+ assert [u1.id] == Enum.map(User.search("laiin"), & &1.id)
+ end
+
+ test "finds users, boosting ranks of friends and followers" do
+ u1 = insert(:user)
+ u2 = insert(:user, %{name: "Doe"})
+ follower = insert(:user, %{name: "Doe"})
+ friend = insert(:user, %{name: "Doe"})
+
+ {:ok, follower} = User.follow(follower, u1)
+ {:ok, u1} = User.follow(u1, friend)
+
+ assert [friend.id, follower.id, u2.id] == Enum.map(User.search("doe", false, u1), & &1.id)
end
test "finds a user whose name is nil" do
@@ -792,7 +839,15 @@ test "finds a user whose name is nil" do
assert user_two ==
User.search("lain@pleroma.soykaf.com")
|> List.first()
- |> Map.put(:search_distance, nil)
+ |> Map.put(:search_rank, nil)
+ end
+
+ test "does not yield false-positive matches" do
+ insert(:user, %{name: "John Doe"})
+
+ Enum.each(["mary", "a", ""], fn query ->
+ assert [] == User.search(query)
+ end)
end
end
@@ -874,4 +929,19 @@ test "returns true when the account is unauthenticated and being viewed by a pri
Pleroma.Config.put([:instance, :account_activation_required], false)
end
end
+
+ describe "parse_bio/2" do
+ test "preserves hosts in user links text" do
+ remote_user = insert(:user, local: false, nickname: "nick@domain.com")
+ user = insert(:user)
+ bio = "A.k.a. @nick@domain.com"
+
+ expected_text =
+ "A.k.a. " <> "@nick@domain.com"
+
+ assert expected_text == User.parse_bio(bio, user)
+ end
+ end
end
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index eafb96f3a..18f094379 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -216,7 +216,7 @@ test "doesn't return blocked activities" do
{:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
- %Activity{} = boost_activity = Activity.get_create_activity_by_object_ap_id(id)
+ %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Repo.get(Activity, activity_three.id)
activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
@@ -330,7 +330,7 @@ test "adds a like activity to the db" do
assert like_activity == same_like_activity
assert object.data["likes"] == [user.ap_id]
- [note_activity] = Activity.all_by_object_ap_id(object.data["id"])
+ [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
assert note_activity.data["object"]["like_count"] == 1
{:ok, _like_activity, object} = ActivityPub.like(user_two, object)
@@ -445,7 +445,7 @@ test "it fetches an object" do
{:ok, object} =
ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
- assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
+ assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
assert activity.data["id"]
{:ok, object_again} =
@@ -459,7 +459,7 @@ test "it fetches an object" do
test "it works with objects only available via Ostatus" do
{:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
- assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
+ assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
assert activity.data["id"]
{:ok, object_again} =
diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
new file mode 100644
index 000000000..2ea4f9d3f
--- /dev/null
+++ b/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
@@ -0,0 +1,57 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy
+
+ describe "blocking based on attributes" do
+ test "matches followbots by nickname" do
+ actor = insert(:user, %{nickname: "followbot@example.com"})
+ target = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Follow",
+ "actor" => actor.ap_id,
+ "object" => target.ap_id,
+ "id" => "https://example.com/activities/1234"
+ }
+
+ {:reject, nil} = AntiFollowbotPolicy.filter(message)
+ end
+
+ test "matches followbots by display name" do
+ actor = insert(:user, %{name: "Federation Bot"})
+ target = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Follow",
+ "actor" => actor.ap_id,
+ "object" => target.ap_id,
+ "id" => "https://example.com/activities/1234"
+ }
+
+ {:reject, nil} = AntiFollowbotPolicy.filter(message)
+ end
+ end
+
+ test "it allows non-followbots" do
+ actor = insert(:user)
+ target = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Follow",
+ "actor" => actor.ap_id,
+ "object" => target.ap_id,
+ "id" => "https://example.com/activities/1234"
+ }
+
+ {:ok, _} = AntiFollowbotPolicy.filter(message)
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 87d0ab559..e5e3c8d33 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -51,7 +51,7 @@ test "it fetches replied-to activities if we don't have them" do
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
assert activity =
- Activity.get_create_activity_by_object_ap_id(
+ Activity.get_create_by_object_ap_id(
"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
)
@@ -162,6 +162,36 @@ test "it works for incoming notices with url not being a string (prismo)" do
assert data["object"]["url"] == "https://prismo.news/posts/83"
end
+ test "it cleans up incoming notices which are not really DMs" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ to = [user.ap_id, other_user.ap_id]
+
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("to", to)
+ |> Map.put("cc", [])
+
+ object =
+ data["object"]
+ |> Map.put("to", to)
+ |> Map.put("cc", [])
+
+ data = Map.put(data, "object", object)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["to"] == []
+ assert data["cc"] == to
+
+ object = data["object"]
+
+ assert object["to"] == []
+ assert object["cc"] == to
+ end
+
test "it works for incoming follow requests" do
user = insert(:user)
@@ -263,7 +293,7 @@ test "it works for incoming announces" do
assert data["object"] ==
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
- assert Activity.get_create_activity_by_object_ap_id(data["object"])
+ assert Activity.get_create_by_object_ap_id(data["object"])
end
test "it works for incoming announces with an existing activity" do
@@ -285,7 +315,23 @@ test "it works for incoming announces with an existing activity" do
assert data["object"] == activity.data["object"]["id"]
- assert Activity.get_create_activity_by_object_ap_id(data["object"]).id == activity.id
+ assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
+ end
+
+ test "it does not clobber the addressing on announce activities" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
+
+ data =
+ File.read!("test/fixtures/mastodon-announce.json")
+ |> Poison.decode!()
+ |> Map.put("object", activity.data["object"]["id"])
+ |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
+ |> Map.put("cc", [])
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
end
test "it works for incoming update activities" do
@@ -856,6 +902,34 @@ test "it adds like collection to object" do
assert modified["object"]["likes"]["type"] == "OrderedCollection"
assert modified["object"]["likes"]["totalItems"] == 0
end
+
+ test "the directMessage flag is present" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == false
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == false
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "@#{other_user.nickname} :moominmamma:",
+ "visibility" => "direct"
+ })
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == true
+ end
end
describe "user upgrade" do
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
new file mode 100644
index 000000000..aeed0564c
--- /dev/null
+++ b/test/web/activity_pub/utils_test.exs
@@ -0,0 +1,57 @@
+defmodule Pleroma.Web.ActivityPub.UtilsTest do
+ use Pleroma.DataCase
+ alias Pleroma.Web.ActivityPub.Utils
+
+ describe "determine_explicit_mentions()" do
+ test "works with an object that has mentions" do
+ object = %{
+ "tag" => [
+ %{
+ "type" => "Mention",
+ "href" => "https://example.com/~alyssa",
+ "name" => "Alyssa P. Hacker"
+ }
+ ]
+ }
+
+ assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
+ end
+
+ test "works with an object that does not have mentions" do
+ object = %{
+ "tag" => [
+ %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
+ ]
+ }
+
+ assert Utils.determine_explicit_mentions(object) == []
+ end
+
+ test "works with an object that has mentions and other tags" do
+ object = %{
+ "tag" => [
+ %{
+ "type" => "Mention",
+ "href" => "https://example.com/~alyssa",
+ "name" => "Alyssa P. Hacker"
+ },
+ %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
+ ]
+ }
+
+ assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
+ end
+
+ test "works with an object that has no tags" do
+ object = %{}
+
+ assert Utils.determine_explicit_mentions(object) == []
+ end
+
+ test "works with an object that has only IR tags" do
+ object = %{"tag" => ["2hu"]}
+
+ assert Utils.determine_explicit_mentions(object) == []
+ end
+ end
+end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 9ac805f24..a7d9e6161 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -17,6 +17,13 @@ test "it de-duplicates tags" do
assert activity.data["object"]["tag"] == ["2hu"]
end
+ test "it adds emoji in the object" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => ":moominmamma:"})
+
+ assert activity.data["object"]["emoji"]["moominmamma"]
+ end
+
test "it adds emoji when updating profiles" do
user = insert(:user, %{name: ":karjalanpiirakka:"})
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index dd84052a3..8443dc856 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
alias Pleroma.Web.{OStatus, CommonAPI}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.MastodonAPI.FilterView
+ alias Ecto.Changeset
import Pleroma.Factory
import ExUnit.CaptureLog
import Tesla.Mock
@@ -1483,6 +1484,16 @@ test "get instance information", %{conn: conn} do
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
+ # Stats should count users with missing or nil `info.deactivated` value
+ user = Repo.get(User, user.id)
+ info_change = Changeset.change(user.info, %{deactivated: nil})
+
+ {:ok, _user} =
+ user
+ |> Changeset.change()
+ |> Changeset.put_embed(:info, info_change)
+ |> User.update_and_set_cache()
+
Pleroma.Stats.update_stats()
conn = get(conn, "/api/v1/instance")
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index d30ae6149..e33479368 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -202,7 +202,7 @@ test "a peertube video" do
"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
)
- %Activity{} = activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
+ %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
represented = StatusView.render("status.json", %{for: user, activity: activity})
diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs
index 905e29d06..16d7b9c24 100644
--- a/test/web/streamer_test.exs
+++ b/test/web/streamer_test.exs
@@ -6,7 +6,8 @@ defmodule Pleroma.Web.StreamerTest do
use Pleroma.DataCase
alias Pleroma.Web.Streamer
- alias Pleroma.{List, User}
+ alias Pleroma.List
+ alias Pleroma.User
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
@@ -35,6 +36,28 @@ test "it sends to public" do
Streamer.push_to_socket(topics, "public", activity)
Task.await(task)
+
+ task =
+ Task.async(fn ->
+ assert_receive {:text, _}, 4_000
+ end)
+
+ fake_socket = %{
+ transport_pid: task.pid,
+ assigns: %{
+ user: user
+ }
+ }
+
+ {:ok, activity} = CommonAPI.delete(activity.id, other_user)
+
+ topics = %{
+ "public" => [fake_socket]
+ }
+
+ Streamer.push_to_socket(topics, "public", activity)
+
+ Task.await(task)
end
test "it doesn't send to blocked users" do
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index e08edc525..863abd10f 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -797,7 +797,7 @@ test "with credentials, invalid activity", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/favorites/create/1.json")
- assert json_response(conn, 500)
+ assert json_response(conn, 400)
end
end
@@ -1621,7 +1621,7 @@ test "it approves a friend request" do
conn =
build_conn()
|> assign(:user, user)
- |> post("/api/pleroma/friendships/approve", %{"user_id" => to_string(other_user.id)})
+ |> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
@@ -1644,7 +1644,7 @@ test "it denies a friend request" do
conn =
build_conn()
|> assign(:user, user)
- |> post("/api/pleroma/friendships/deny", %{"user_id" => to_string(other_user.id)})
+ |> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
@@ -1655,16 +1655,16 @@ test "it denies a friend request" do
describe "GET /api/pleroma/search_user" do
test "it returns users, ordered by similarity", %{conn: conn} do
user = insert(:user, %{name: "eal"})
- user_two = insert(:user, %{name: "ean"})
- user_three = insert(:user, %{name: "ebn"})
+ user_two = insert(:user, %{name: "eal me"})
+ _user_three = insert(:user, %{name: "zzz"})
resp =
conn
- |> get(twitter_api_search__path(conn, :search_user), query: "eal")
+ |> get(twitter_api_search__path(conn, :search_user), query: "eal me")
|> json_response(200)
- assert length(resp) == 3
- assert [user.id, user_two.id, user_three.id] == Enum.map(resp, fn %{"id" => id} -> id end)
+ assert length(resp) == 2
+ assert [user_two.id, user.id] == Enum.map(resp, fn %{"id" => id} -> id end)
end
end
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 547592ff2..f94e2b873 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -451,7 +451,7 @@ test "fetches a user by uri" do
assert represented["id"] == UserView.render("show.json", %{user: remote, for: user})["id"]
# Also fetches the feed.
- # assert Activity.get_create_activity_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status")
+ # assert Activity.get_create_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status")
end
end
end
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index 3d6b264b1..ba053d20d 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -344,7 +344,7 @@ test "a peertube video" do
"https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
)
- %Activity{} = activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
+ %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
result = ActivityView.render("activity.json", activity: activity)
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 5f7481eb6..daf18c1c5 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -100,6 +100,7 @@ test "A user" do
"locked" => false,
"default_scope" => "public",
"no_rich_text" => false,
+ "hide_network" => false,
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
@@ -146,6 +147,7 @@ test "A user for a given other follower", %{user: user} do
"locked" => false,
"default_scope" => "public",
"no_rich_text" => false,
+ "hide_network" => false,
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
@@ -193,6 +195,7 @@ test "A user that follows you", %{user: user} do
"locked" => false,
"default_scope" => "public",
"no_rich_text" => false,
+ "hide_network" => false,
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,
@@ -254,6 +257,7 @@ test "A blocked user for the blocker" do
"locked" => false,
"default_scope" => "public",
"no_rich_text" => false,
+ "hide_network" => false,
"fields" => [],
"pleroma" => %{
"confirmation_pending" => false,