diff --git a/README.md b/README.md
index 664b8b475..fcf296c01 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ No release has been made yet, but several servers have been online for months al
### Dependencies
* Postgresql version 9.6 or newer
-* Elixir version 1.4 or newer (you will also need erlang-dev, erlang-parsetools, erlang-xmerl packages)
+* Elixir version 1.5 or newer
* Build-essential tools
### Configuration
@@ -50,3 +50,12 @@ Logs can be watched by using `journalctl -fu pleroma.service`
### Standalone/run by other means
Run `mix phx.server` in repository's root, it will output log into stdout/stderr
+
+### Using an upstream proxy for federation
+
+Add the following to your `dev.secret.exs` or `prod.secret.exs` if you want to proxify all http requests that pleroma makes to an upstream proxy server:
+
+ config :pleroma, :http,
+ proxy_url: "127.0.0.1:8123"
+
+This is useful for running pleroma inside Tor or i2p.
diff --git a/config/config.exs b/config/config.exs
index f26f9ecdf..e6c695215 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -33,7 +33,7 @@
config :pleroma, :websub, Pleroma.Web.Websub
config :pleroma, :ostatus, Pleroma.Web.OStatus
-config :pleroma, :httpoison, HTTPoison
+config :pleroma, :httpoison, Pleroma.HTTP
version = with {version, 0} <- System.cmd("git", ["rev-parse", "HEAD"]) do
"Pleroma #{String.trim(version)}"
@@ -41,6 +41,10 @@
_ -> "Pleroma dev"
end
+# Configures http settings, upstream proxy etc.
+config :pleroma, :http,
+ proxy_url: nil
+
config :pleroma, :instance,
version: version,
name: "Pleroma",
@@ -48,6 +52,14 @@
limit: 5000,
registrations_open: true
+config :pleroma, :media_proxy,
+ enabled: false,
+ redirect_on_failure: true
+ #base_url: "https://cache.pleroma.social"
+
+config :pleroma, :chat,
+ enabled: true
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs"
diff --git a/config/emoji.txt b/config/emoji.txt
index 0e668e609..7afacb09f 100644
--- a/config/emoji.txt
+++ b/config/emoji.txt
@@ -1 +1,31 @@
firefox, /emoji/Firefox.gif
+blank, /emoji/blank.png
+f_00b, /emoji/f_00b.png
+f_00b11b, /emoji/f_00b11b.png
+f_00b33b, /emoji/f_00b33b.png
+f_00h, /emoji/f_00h.png
+f_00t, /emoji/f_00t.png
+f_01b, /emoji/f_01b.png
+f_03b, /emoji/f_03b.png
+f_10b, /emoji/f_10b.png
+f_11b, /emoji/f_11b.png
+f_11b00b, /emoji/f_11b00b.png
+f_11b22b, /emoji/f_11b22b.png
+f_11h, /emoji/f_11h.png
+f_11t, /emoji/f_11t.png
+f_12b, /emoji/f_12b.png
+f_21b, /emoji/f_21b.png
+f_22b, /emoji/f_22b.png
+f_22b11b, /emoji/f_22b11b.png
+f_22b33b, /emoji/f_22b33b.png
+f_22h, /emoji/f_22h.png
+f_22t, /emoji/f_22t.png
+f_23b, /emoji/f_23b.png
+f_30b, /emoji/f_30b.png
+f_32b, /emoji/f_32b.png
+f_33b, /emoji/f_33b.png
+f_33b00b, /emoji/f_33b00b.png
+f_33b22b, /emoji/f_33b22b.png
+f_33h, /emoji/f_33h.png
+f_33t, /emoji/f_33t.png
+
diff --git a/config/prod.exs b/config/prod.exs
index 732bab2b0..8522c67da 100644
--- a/config/prod.exs
+++ b/config/prod.exs
@@ -14,9 +14,12 @@
# manifest is generated by the mix phoenix.digest task
# which you typically run after static files are built.
config :pleroma, Pleroma.Web.Endpoint,
- on_init: {Pleroma.Web.Endpoint, :load_from_system_env, []},
- url: [host: "example.com", port: 80],
- cache_static_manifest: "priv/static/cache_manifest.json"
+ http: [port: 4000],
+ protocol: "http",
+ debug_errors: true,
+ code_reloader: true,
+ check_origin: false,
+ watchers: []
# Do not print debug messages in production
config :logger, level: :info
diff --git a/installation/Caddyfile b/installation/Caddyfile
new file mode 100644
index 000000000..08d5e6169
--- /dev/null
+++ b/installation/Caddyfile
@@ -0,0 +1,5 @@
+instance.example.com { # Your instance's domain
+ proxy / localhost:4000 {
+ websocket
+ }
+}
diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx
index 6cf9f3fa0..f714792da 100644
--- a/installation/pleroma.nginx
+++ b/installation/pleroma.nginx
@@ -1,3 +1,6 @@
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g
+ inactive=720m use_temp_path=off;
+
server {
listen 80;
server_name example.tld;
@@ -19,11 +22,17 @@ server {
server_name example.tld;
location / {
+ add_header 'Access-Control-Allow-Origin' '*';
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:4000;
}
- include snippets/well-known.conf;
-}
\ No newline at end of file
+ location /proxy {
+ proxy_cache pleroma_media_cache;
+ proxy_cache_lock on;
+ proxy_pass http://localhost:4000;
+ }
+
+}
diff --git a/lib/mix/tasks/generate_config.ex b/lib/mix/tasks/generate_config.ex
index f20f93e4d..2d962124f 100644
--- a/lib/mix/tasks/generate_config.ex
+++ b/lib/mix/tasks/generate_config.ex
@@ -8,11 +8,20 @@ def run(_) do
domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim
name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim
email = IO.gets("What's your admin email address: ") |> String.trim
+ mediaproxy = IO.gets("Do you want to activate the mediaproxy? (y/N): ")
+ |> String.trim()
+ |> String.downcase()
+ |> String.starts_with?("y")
+ proxy_url = if mediaproxy do
+ IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ") |> String.trim
+ else
+ "https://cache.example.com"
+ end
secret = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", [dbpass: dbpass])
- result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, dbpass: dbpass])
+ result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, proxy_url: proxy_url, dbpass: dbpass])
IO.puts("\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs")
File.write("config/generated_config.exs", result)
diff --git a/lib/mix/tasks/sample_config.eex b/lib/mix/tasks/sample_config.eex
index 85a7c554e..9330fae2d 100644
--- a/lib/mix/tasks/sample_config.eex
+++ b/lib/mix/tasks/sample_config.eex
@@ -10,6 +10,11 @@ config :pleroma, :instance,
limit: 5000,
registrations_open: true
+config :pleroma, :media_proxy,
+ enabled: <%= mediaproxy %>,
+ redirect_on_failure: true,
+ base_url: "<%= proxy_url %>"
+
# Configure your database
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 2969ca3c4..79b9dee9d 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -20,13 +20,18 @@ def start(_type, _args) do
limit: 2500
]]),
worker(Pleroma.Web.Federator, []),
- worker(Pleroma.Web.ChatChannel.ChatChannelState, []),
+ worker(Pleroma.Stats, []),
]
++ if Mix.env == :test, do: [], else: [worker(Pleroma.Web.Streamer, [])]
+ ++ if !chat_enabled(), do: [], else: [worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
Supervisor.start_link(children, opts)
end
+
+ defp chat_enabled do
+ Application.get_env(:pleroma, :chat, []) |> Keyword.get(:enabled)
+ end
end
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index c98db2d94..fdf91f56e 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -1,5 +1,6 @@
defmodule Pleroma.Formatter do
alias Pleroma.User
+ alias Pleroma.Web.MediaProxy
@link_regex ~r/https?:\/\/[\w\.\/?=\-#%&@~\(\)]+[\w\/]/u
def linkify(text) do
@@ -10,7 +11,7 @@ def linkify(text) do
def parse_tags(text, data \\ %{}) do
Regex.scan(@tag_regex, text)
|> Enum.map(fn (["#" <> tag = full_tag]) -> {full_tag, String.downcase(tag)} end)
- |> (fn map -> if data["sensitive"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
+ |> (fn map -> if data["sensitive"] in [true, "True", "true", "1"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
end
def parse_mentions(text) do
@@ -103,13 +104,19 @@ def html_escape(text) do
{finmoji, "/finmoji/128px/#{finmoji}-128.png"}
end)
- @emoji_from_file (with {:ok, file} <- File.read("config/emoji.txt") do
- file
- |> String.trim
- |> String.split("\n")
- |> Enum.map(fn(line) ->
- [name, file] = String.split(line, ", ")
- {name, file}
+ @emoji_from_file (with {:ok, default} <- File.read("config/emoji.txt") do
+ custom =
+ with {:ok, custom} <- File.read("config/custom_emoji.txt") do
+ custom
+ else
+ _e -> ""
+ end
+ (default <> "\n" <> custom)
+ |> String.trim()
+ |> String.split(~r/\n+/)
+ |> Enum.map(fn(line) ->
+ [name, file] = String.split(line, ~r/,\s*/)
+ {name, file}
end)
else
_ -> []
@@ -125,7 +132,7 @@ def emojify(text, additional \\ nil) do
end
Enum.reduce(all_emoji, text, fn ({emoji, file}, text) ->
- String.replace(text, ":#{emoji}:", "")
+ String.replace(text, ":#{emoji}:", "")
end)
end
diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex
new file mode 100644
index 000000000..8b8a82353
--- /dev/null
+++ b/lib/pleroma/http/http.ex
@@ -0,0 +1,14 @@
+
+defmodule Pleroma.HTTP do
+ use HTTPoison.Base
+
+ def process_request_options(options) do
+ config = Application.get_env(:pleroma, :http, [])
+ proxy = Keyword.get(config, :proxy_url, nil)
+ case proxy do
+ nil -> options
+ _ -> options ++ [proxy: proxy]
+ end
+ end
+
+end
diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
new file mode 100644
index 000000000..737e9b62e
--- /dev/null
+++ b/lib/pleroma/stats.ex
@@ -0,0 +1,41 @@
+defmodule Pleroma.Stats do
+ import Ecto.Query
+ alias Pleroma.{User, Repo, Activity}
+
+ def start_link do
+ agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
+ spawn(fn -> schedule_update() end)
+ agent
+ end
+
+ def get_stats do
+ Agent.get(__MODULE__, fn {_, stats} -> stats end)
+ end
+
+ def get_peers do
+ Agent.get(__MODULE__, fn {peers, _} -> peers end)
+ end
+
+ def schedule_update do
+ spawn(fn ->
+ Process.sleep(1000 * 60 * 60 * 1) # 1 hour
+ schedule_update()
+ end)
+ update_stats()
+ end
+
+ def update_stats do
+ peers = from(u in Pleroma.User,
+ select: fragment("distinct ?->'host'", u.info),
+ where: u.local != ^true)
+ |> Repo.all()
+ domain_count = Enum.count(peers)
+ status_query = from(u in User.local_user_query,
+ select: fragment("sum((?->>'note_count')::int)", u.info))
+ status_count = Repo.one(status_query) |> IO.inspect
+ user_count = Repo.aggregate(User.local_user_query, :count, :id)
+ Agent.update(__MODULE__, fn _ ->
+ {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
+ end)
+ end
+end
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
index 3567c6c88..c41617c68 100644
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -9,7 +9,7 @@ def store(%Plug.Upload{} = file) do
File.cp!(file.path, result_file)
# fix content type on some image uploads
- content_type = if file.content_type == "application/octet-stream" do
+ content_type = if file.content_type in [nil, "application/octet-stream"] do
get_content_type(file.path)
else
file.content_type
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 4580f30fb..e544d3772 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -29,14 +29,14 @@ defmodule Pleroma.User do
def avatar_url(user) do
case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href
- _ -> "https://placehold.it/48x48"
+ _ -> "#{Web.base_url()}/images/avi.png"
end
end
def banner_url(user) do
case user.info["banner"] do
%{"url" => [%{"href" => href} | _]} -> href
- _ -> nil
+ _ -> "#{Web.base_url()}/images/banner.png"
end
end
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 4a9bb8e22..f18b3cb80 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -5,7 +5,9 @@ defmodule Pleroma.Web.UserSocket do
## Channels
# channel "room:*", Pleroma.Web.RoomChannel
- channel "chat:*", Pleroma.Web.ChatChannel
+ if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
+ channel "chat:*", Pleroma.Web.ChatChannel
+ end
## Transports
transport :websocket, Phoenix.Transports.WebSocket
diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex
index 268bef17d..48a3553bf 100644
--- a/lib/pleroma/web/chat_channel.ex
+++ b/lib/pleroma/web/chat_channel.ex
@@ -24,7 +24,6 @@ def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}}
end
defmodule Pleroma.Web.ChatChannel.ChatChannelState do
- use Agent
@max_messages 20
def start_link do
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index e60dff7dc..2b359dd72 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -95,7 +95,7 @@ def add_user_links(text, mentions) do
Enum.reduce(mentions, step_one, fn ({match, %User{ap_id: ap_id}, uuid}, text) ->
short_match = String.split(match, "@") |> tl() |> hd()
- String.replace(text, uuid, "@#{short_match}")
+ String.replace(text, uuid, "@#{short_match}")
end)
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index b57cf3917..93b37dc74 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -1,7 +1,9 @@
defmodule Pleroma.Web.Endpoint do
use Phoenix.Endpoint, otp_app: :pleroma
- socket "/socket", Pleroma.Web.UserSocket
+ if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
+ socket "/socket", Pleroma.Web.UserSocket
+ end
socket "/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket
# Serve at "/" the static files from "priv/static" directory.
@@ -12,7 +14,7 @@ defmodule Pleroma.Web.Endpoint do
at: "/media", from: "uploads", gzip: false
plug Plug.Static,
at: "/", from: :pleroma,
- only: ~w(index.html static finmoji emoji packs sounds sw.js)
+ only: ~w(index.html static finmoji emoji packs sounds images instance sw.js)
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index b23ed5fcc..c9f9dc7a1 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -41,12 +41,12 @@ def handle(:request_subscription, websub) do
def handle(:publish, activity) do
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do
- Logger.debug(fn -> "Sending #{activity.data["id"]} out via websub" end)
- Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)
-
{:ok, actor} = WebFinger.ensure_keys_present(actor)
Logger.debug(fn -> "Sending #{activity.data["id"]} out via salmon" end)
Pleroma.Web.Salmon.publish(actor, activity)
+
+ Logger.debug(fn -> "Sending #{activity.data["id"]} out via websub" end)
+ Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)
end
end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index e50f53ba4..e16a2a092 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1,6 +1,6 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
- alias Pleroma.{Repo, Activity, User, Notification}
+ alias Pleroma.{Repo, Activity, User, Notification, Stats}
alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView}
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -93,7 +93,6 @@ def user(conn, %{"id" => id}) do
@instance Application.get_env(:pleroma, :instance)
def masto_instance(conn, _params) do
- user_count = Repo.aggregate(User.local_user_query, :count, :id)
response = %{
uri: Web.base_url,
title: Keyword.get(@instance, :name),
@@ -103,17 +102,18 @@ def masto_instance(conn, _params) do
urls: %{
streaming_api: String.replace(Web.base_url, ["http","https"], "wss")
},
- stats: %{
- status_count: 2,
- user_count: user_count,
- domain_count: 3
- },
+ stats: Stats.get_stats,
+ thumbnail: Web.base_url <> "/instance/thumbnail.jpeg",
max_toot_chars: Keyword.get(@instance, :limit)
}
json(conn, response)
end
+ def peers(conn, _params) do
+ json(conn, Stats.get_peers)
+ end
+
defp mastodonized_emoji do
Pleroma.Formatter.get_custom_emoji()
|> Enum.map(fn {shortcode, relative_url} ->
@@ -162,7 +162,7 @@ def home_timeline(%{assigns: %{user: user}} = conn, params) do
def public_timeline(%{assigns: %{user: user}} = conn, params) do
params = params
|> Map.put("type", ["Create", "Announce"])
- |> Map.put("local_only", !!params["local"])
+ |> Map.put("local_only", params["local"] in [true, "True", "true", "1"])
|> Map.put("blocking_user", user)
activities = ActivityPub.fetch_public_activities(params)
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 02f1e60bb..d2a4dd366 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -3,20 +3,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
alias Pleroma.User
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.CommonAPI.Utils
-
- defp image_url(%{"url" => [ %{ "href" => href } | _ ]}), do: href
- defp image_url(_), do: nil
+ alias Pleroma.Web.MediaProxy
def render("accounts.json", %{users: users} = opts) do
render_many(users, AccountView, "account.json", opts)
end
def render("account.json", %{user: user}) do
- image = User.avatar_url(user)
+ image = User.avatar_url(user) |> MediaProxy.url()
+ header = User.banner_url(user) |> MediaProxy.url()
user_info = User.user_info(user)
- header = image_url(user.info["banner"]) || "https://placehold.it/700x335"
-
%{
id: to_string(user.id),
username: hd(String.split(user.nickname, "@")),
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 5585a5605..64f315597 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -3,6 +3,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Web.MastodonAPI.{AccountView, StatusView}
alias Pleroma.{User, Activity}
alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.MediaProxy
def render("index.json", opts) do
render_many(opts.activities, StatusView, "status.json", opts)
@@ -121,9 +122,9 @@ def render("attachment.json", %{attachment: attachment}) do
%{
id: to_string(attachment["id"] || hash_id),
- url: href,
+ url: MediaProxy.url(href),
remote_url: href,
- preview_url: href,
+ preview_url: MediaProxy.url(href),
text_url: href,
type: type
}
diff --git a/lib/pleroma/web/media_proxy/controller.ex b/lib/pleroma/web/media_proxy/controller.ex
new file mode 100644
index 000000000..9327e7253
--- /dev/null
+++ b/lib/pleroma/web/media_proxy/controller.ex
@@ -0,0 +1,84 @@
+defmodule Pleroma.Web.MediaProxy.MediaProxyController do
+ use Pleroma.Web, :controller
+ require Logger
+
+ @httpoison Application.get_env(:pleroma, :httpoison)
+
+ @max_body_length 25 * 1048576
+
+ @cache_control %{
+ default: "public, max-age=1209600",
+ error: "public, must-revalidate, max-age=160",
+ }
+
+ def remote(conn, %{"sig" => sig, "url" => url}) do
+ config = Application.get_env(:pleroma, :media_proxy, [])
+ with \
+ true <- Keyword.get(config, :enabled, false),
+ {:ok, url} <- Pleroma.Web.MediaProxy.decode_url(sig, url),
+ {:ok, content_type, body} <- proxy_request(url)
+ do
+ conn
+ |> put_resp_content_type(content_type)
+ |> set_cache_header(:default)
+ |> send_resp(200, body)
+ else
+ false -> send_error(conn, 404)
+ {:error, :invalid_signature} -> send_error(conn, 403)
+ {:error, {:http, _, url}} -> redirect_or_error(conn, url, Keyword.get(config, :redirect_on_failure, true))
+ end
+ end
+
+ defp proxy_request(link) do
+ headers = [{"user-agent", "Pleroma/MediaProxy; #{Pleroma.Web.base_url()} <#{Application.get_env(:pleroma, :instance)[:email]}>"}]
+ options = @httpoison.process_request_options([:insecure, {:follow_redirect, true}])
+ with \
+ {:ok, 200, headers, client} <- :hackney.request(:get, link, headers, "", options),
+ headers = Enum.into(headers, Map.new),
+ {:ok, body} <- proxy_request_body(client),
+ content_type <- proxy_request_content_type(headers, body)
+ do
+ {:ok, content_type, body}
+ else
+ {:ok, status, _, _} ->
+ Logger.warn "MediaProxy: request failed, status #{status}, link: #{link}"
+ {:error, {:http, :bad_status, link}}
+ {:error, error} ->
+ Logger.warn "MediaProxy: request failed, error #{inspect error}, link: #{link}"
+ {:error, {:http, error, link}}
+ end
+ end
+
+ defp set_cache_header(conn, key) do
+ Plug.Conn.put_resp_header(conn, "cache-control", @cache_control[key])
+ end
+
+ defp redirect_or_error(conn, url, true), do: redirect(conn, external: url)
+ defp redirect_or_error(conn, url, _), do: send_error(conn, 502, "Media proxy error: " <> url)
+
+ defp send_error(conn, code, body \\ "") do
+ conn
+ |> set_cache_header(:error)
+ |> send_resp(code, body)
+ end
+
+ defp proxy_request_body(client), do: proxy_request_body(client, <<>>)
+ defp proxy_request_body(client, body) when byte_size(body) < @max_body_length do
+ case :hackney.stream_body(client) do
+ {:ok, data} -> proxy_request_body(client, <
>)
+ :done -> {:ok, body}
+ {:error, reason} -> {:error, reason}
+ end
+ end
+ defp proxy_request_body(client, _) do
+ :hackney.close(client)
+ {:error, :body_too_large}
+ end
+
+ # TODO: the body is passed here as well because some hosts do not provide a content-type.
+ # At some point we may want to use magic numbers to discover the content-type and reply a proper one.
+ defp proxy_request_content_type(headers, _body) do
+ headers["Content-Type"] || headers["content-type"] || "image/jpeg"
+ end
+
+end
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
new file mode 100644
index 000000000..23efc18fa
--- /dev/null
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -0,0 +1,32 @@
+defmodule Pleroma.Web.MediaProxy do
+ @base64_opts [padding: false]
+
+ def url(nil), do: nil
+
+ def url(url = "/" <> _), do: url
+
+ def url(url) do
+ config = Application.get_env(:pleroma, :media_proxy, [])
+ if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url) do
+ url
+ else
+ secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
+ base64 = Base.url_encode64(url, @base64_opts)
+ sig = :crypto.hmac(:sha, secret, base64)
+ sig64 = sig |> Base.url_encode64(@base64_opts)
+ Keyword.get(config, :base_url, Pleroma.Web.base_url) <> "/proxy/#{sig64}/#{base64}"
+ end
+ end
+
+ def decode_url(sig, url) do
+ secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
+ sig = Base.url_decode64!(sig, @base64_opts)
+ local_sig = :crypto.hmac(:sha, secret, url)
+ if local_sig == sig do
+ {:ok, Base.url_decode64!(url, @base64_opts)}
+ else
+ {:error, :invalid_signature}
+ end
+ end
+
+end
diff --git a/lib/pleroma/web/oauth/fallback_controller.ex b/lib/pleroma/web/oauth/fallback_controller.ex
new file mode 100644
index 000000000..daa110532
--- /dev/null
+++ b/lib/pleroma/web/oauth/fallback_controller.ex
@@ -0,0 +1,12 @@
+defmodule Pleroma.Web.OAuth.FallbackController do
+ use Pleroma.Web, :controller
+ alias Pleroma.Web.OAuth.OAuthController
+
+ # No user/password
+ def call(conn, _) do
+ conn
+ |> put_flash(:error, "Invalid Username/Password")
+ |> OAuthController.authorize(conn.params)
+ end
+
+end
\ No newline at end of file
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index e8483dec0..94318bfa9 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,6 +5,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.{Repo, User}
alias Comeonin.Pbkdf2
+ plug :fetch_session
+ plug :fetch_flash
+
+ action_fallback Pleroma.Web.OAuth.FallbackController
+
def authorize(conn, params) do
render conn, "show.html", %{
response_type: params["response_type"],
diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex
index 08710f246..10860ce04 100644
--- a/lib/pleroma/web/ostatus/feed_representer.ex
+++ b/lib/pleroma/web/ostatus/feed_representer.ex
@@ -1,6 +1,8 @@
defmodule Pleroma.Web.OStatus.FeedRepresenter do
alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.{UserRepresenter, ActivityRepresenter}
+ alias Pleroma.User
+ alias Pleroma.Web.MediaProxy
def to_simple_form(user, activities, _users) do
most_recent_update = (List.first(activities) || user).updated_at
@@ -25,6 +27,7 @@ def to_simple_form(user, activities, _users) do
{:id, h.(OStatus.feed_path(user))},
{:title, ['#{user.nickname}\'s timeline']},
{:updated, h.(most_recent_update)},
+ {:logo, [to_charlist(User.avatar_url(user) |> MediaProxy.url())]},
{:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []},
{:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []},
{:link, [rel: 'self', href: h.(OStatus.feed_path(user)), type: 'application/atom+xml'], []},
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index 745539b3e..c35ba42be 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -22,6 +22,10 @@ def salmon_path(user) do
"#{user.ap_id}/salmon"
end
+ def remote_follow_path do
+ "#{Web.base_url}/ostatus_subscribe?acct={uri}"
+ end
+
def handle_incoming(xml_string) do
with doc when doc != :error <- parse_document(xml_string) do
entries = :xmerl_xpath.string('//entry', doc)
@@ -159,8 +163,7 @@ def get_content(entry) do
Get the cw that mastodon uses.
"""
def get_cw(entry) do
- with scope when not is_nil(scope) <- string_from_xpath("//mastodon:scope", entry),
- cw when not is_nil(cw) <- string_from_xpath("/*/summary", entry) do
+ with cw when not is_nil(cw) <- string_from_xpath("/*/summary", entry) do
cw
else _e -> nil
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 4f9ebf5e8..6455ff108 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -28,6 +28,13 @@ def user_fetcher(username) do
plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
end
+ pipeline :pleroma_html do
+ plug :accepts, ["html"]
+ plug :fetch_session
+ plug Pleroma.Plugs.OAuthPlug
+ plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+ end
+
pipeline :well_known do
plug :accepts, ["xml", "xrd+xml"]
end
@@ -51,6 +58,18 @@ def user_fetcher(username) do
get "/emoji", UtilController, :emoji
end
+ scope "/", Pleroma.Web.TwitterAPI do
+ pipe_through :pleroma_html
+ get "/ostatus_subscribe", UtilController, :remote_follow
+ post "/ostatus_subscribe", UtilController, :do_remote_follow
+ post "/main/ostatus", UtilController, :remote_subscribe
+ end
+
+ scope "/api/pleroma", Pleroma.Web.TwitterAPI do
+ pipe_through :authenticated_api
+ post "/follow_import", UtilController, :follow_import
+ end
+
scope "/oauth", Pleroma.Web.OAuth do
get "/authorize", OAuthController, :authorize
post "/authorize", OAuthController, :create_authorization
@@ -101,6 +120,7 @@ def user_fetcher(username) do
scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through :api
get "/instance", MastodonAPIController, :masto_instance
+ get "/instance/peers", MastodonAPIController, :peers
post "/apps", MastodonAPIController, :create_app
get "/custom_emojis", MastodonAPIController, :custom_emojis
@@ -142,6 +162,8 @@ def user_fetcher(username) do
get "/qvitter/statuses/user_timeline", TwitterAPI.Controller, :user_timeline
get "/users/show", TwitterAPI.Controller, :show_user
+ get "/statuses/followers", TwitterAPI.Controller, :followers
+ get "/statuses/friends", TwitterAPI.Controller, :friends
get "/statuses/show/:id", TwitterAPI.Controller, :fetch_status
get "/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation
@@ -188,8 +210,6 @@ def user_fetcher(username) do
post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar
- get "/statuses/followers", TwitterAPI.Controller, :followers
- get "/statuses/friends", TwitterAPI.Controller, :friends
get "/friends/ids", TwitterAPI.Controller, :friends_ids
get "/friendships/no_retweets/ids", TwitterAPI.Controller, :empty_array
@@ -243,6 +263,14 @@ def user_fetcher(username) do
delete "/auth/sign_out", MastodonAPIController, :logout
end
+ pipeline :remote_media do
+ plug :accepts, ["html"]
+ end
+ scope "/proxy/", Pleroma.Web.MediaProxy do
+ pipe_through :remote_media
+ get "/:sig/:url", MediaProxyController, :remote
+ end
+
scope "/", Fallback do
get "/*path", RedirectController, :redirector
end
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index 3c6903a16..a7fa7523b 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -1,3 +1,5 @@
+<%= get_flash(@conn, :info) %>
+<%= get_flash(@conn, :error) %>
OAuth Authorization
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
<%= label f, :name, "Name" %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
new file mode 100644
index 000000000..06359fa6c
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
@@ -0,0 +1,11 @@
+<%= if @error == :error do %>
+ Error fetching user
+<% else %>
+ Remote follow
+
+ <%= @name %>
+ <%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "user"], fn f -> %>
+ <%= hidden_input f, :id, value: @id %>
+ <%= submit "Authorize" %>
+ <% end %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
new file mode 100644
index 000000000..4e3a2be67
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
@@ -0,0 +1,14 @@
+<%= if @error do %>
+ <%= @error %>
+<% end %>
+Log in to follow
+<%= @name %>
+
+<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "authorization"], fn f -> %>
+<%= text_input f, :name, placeholder: "Username" %>
+
+<%= password_input f, :password, placeholder: "Password" %>
+
+<%= hidden_input f, :id, value: @id %>
+<%= submit "Authorize" %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
new file mode 100644
index 000000000..da473d502
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
@@ -0,0 +1,6 @@
+<%= if @error do %>
+Error following account
+<% else %>
+Account followed!
+<% end %>
+
diff --git a/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex
new file mode 100644
index 000000000..f60accebf
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex
@@ -0,0 +1,10 @@
+<%= if @error do %>
+ Error: <%= @error %>
+<% else %>
+ Remotely follow <%= @nickname %>
+ <%= form_for @conn, util_path(@conn, :remote_subscribe), [as: "user"], fn f -> %>
+ <%= hidden_input f, :nickname, value: @nickname %>
+ <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %>
+ <%= submit "Follow" %>
+ <% end %>
+<% end %>
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index de2abd4d1..503719dbf 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -1,8 +1,12 @@
defmodule Pleroma.Web.TwitterAPI.UtilController do
use Pleroma.Web, :controller
+ require Logger
alias Pleroma.Web
+ alias Pleroma.Web.OStatus
+ alias Pleroma.Web.WebFinger
+ alias Comeonin.Pbkdf2
alias Pleroma.Formatter
-
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.{Repo, PasswordResetToken, User}
def show_password_reset(conn, %{"token" => token}) do
@@ -29,6 +33,72 @@ def help_test(conn, _params) do
json(conn, "ok")
end
+ def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
+ with %User{} = user <- User.get_cached_by_nickname(nick),
+ avatar = User.avatar_url(user) do
+ conn
+ |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
+ else
+ _e -> render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Could not find user"})
+ end
+ end
+ def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
+ with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
+ %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
+ conn
+ |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
+ else
+ _e ->
+ render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Something went wrong."})
+ end
+ end
+
+ def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
+ {err, followee} = OStatus.find_or_make_user(acct)
+ avatar = User.avatar_url(followee)
+ name = followee.nickname
+ id = followee.id
+
+ if !!user do
+ conn
+ |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+ else
+ conn
+ |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
+ end
+ end
+
+ def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
+ followee = Repo.get(User, id)
+ avatar = User.avatar_url(followee)
+ name = followee.nickname
+ with %User{} = user <- User.get_cached_by_nickname(username),
+ true <- Pbkdf2.checkpw(password, user.password_hash),
+ %User{} = followed <- Repo.get(User, id),
+ {:ok, follower} <- User.follow(user, followee),
+ {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+ conn
+ |> render("followed.html", %{error: false})
+ else
+ _e ->
+ conn
+ |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
+ end
+ end
+ def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
+ with %User{} = followee <- Repo.get(User, id),
+ {:ok, follower} <- User.follow(user, followee),
+ {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+ conn
+ |> render("followed.html", %{error: false})
+ else
+ e ->
+ Logger.debug("Remote follow failed with error #{inspect e}")
+ conn
+ |> render("followed.html", %{error: inspect(e)})
+ end
+ end
+
@instance Application.get_env(:pleroma, :instance)
def config(conn, _params) do
case get_format(conn) do
@@ -51,7 +121,7 @@ def config(conn, _params) do
site: %{
name: Keyword.get(@instance, :name),
server: Web.base_url,
- textlimit: Keyword.get(@instance, :limit),
+ textlimit: to_string(Keyword.get(@instance, :limit)),
closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1")
}
})
@@ -73,4 +143,24 @@ def version(conn, _params) do
def emoji(conn, _params) do
json conn, Enum.into(Formatter.get_custom_emoji(), %{})
end
+
+ def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
+ follow_import(conn, %{"list" => File.read!(listfile.path)})
+ end
+ def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do
+ Task.start(fn ->
+ String.split(list)
+ |> Enum.map(fn nick ->
+ with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id),
+ %User{} = followed <- User.get_or_fetch_by_nickname(nick),
+ {:ok, follower} <- User.follow(follower, followed) do
+ ActivityPub.follow(follower, followed)
+ else
+ _e -> Logger.debug "follow_import: following #{nick} failed"
+ end
+ end)
+ end)
+
+ json conn, "job started"
+ end
end
diff --git a/lib/pleroma/web/twitter_api/representers/object_representer.ex b/lib/pleroma/web/twitter_api/representers/object_representer.ex
index c39b60760..69eaeb36c 100644
--- a/lib/pleroma/web/twitter_api/representers/object_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/object_representer.ex
@@ -6,7 +6,7 @@ def to_map(%Object{} = object, _opts) do
data = object.data
url = List.first(data["url"])
%{
- url: url["href"],
+ url: url["href"] |> Pleroma.Web.MediaProxy.url(),
mimetype: url["mediaType"],
id: data["uuid"],
oembed: false
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index d04a81cd4..faecebde0 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -316,10 +316,12 @@ def conversation_id_to_context(id) do
def get_external_profile(for_user, uri) do
with {:ok, %User{} = user} <- OStatus.find_or_make_user(uri) do
- with url <- user.info["topic"],
- {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
- OStatus.handle_incoming(body)
- end
+ spawn(fn ->
+ with url <- user.info["topic"],
+ {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
+ OStatus.handle_incoming(body)
+ end
+ end)
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
else _e ->
{:error, "Couldn't find user"}
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 73d96c73d..5284a8847 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -263,16 +263,18 @@ def update_most_recent_notification(%{assigns: %{user: user}} = conn, %{"id" =>
end
end
- def followers(%{assigns: %{user: user}} = conn, _params) do
- with {:ok, followers} <- User.get_followers(user) do
+ def followers(conn, params) do
+ with {:ok, user} <- TwitterAPI.get_user(conn.assigns.user, params),
+ {:ok, followers} <- User.get_followers(user) do
render(conn, UserView, "index.json", %{users: followers, for: user})
else
_e -> bad_request_reply(conn, "Can't get followers")
end
end
- def friends(%{assigns: %{user: user}} = conn, _params) do
- with {:ok, friends} <- User.get_friends(user) do
+ def friends(conn, params) do
+ with {:ok, user} <- TwitterAPI.get_user(conn.assigns.user, params),
+ {:ok, friends} <- User.get_friends(user) do
render(conn, UserView, "index.json", %{users: friends, for: user})
else
_e -> bad_request_reply(conn, "Can't get friends")
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index d1c7e6fbd..f49bcc0fb 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -2,6 +2,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
use Pleroma.Web, :view
alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.MediaProxy
def render("show.json", %{user: user = %User{}} = assigns) do
render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns)
@@ -12,7 +13,7 @@ def render("index.json", %{users: users, for: user}) do
end
def render("user.json", %{user: user = %User{}} = assigns) do
- image = User.avatar_url(user)
+ image = User.avatar_url(user) |> MediaProxy.url()
{following, follows_you, statusnet_blocking} = if assigns[:for] do
{
User.following?(assigns[:for], user),
@@ -44,8 +45,9 @@ def render("user.json", %{user: user = %User{}} = assigns) do
"screen_name" => user.nickname,
"statuses_count" => user_info[:note_count],
"statusnet_profile_url" => user.ap_id,
- "cover_photo" => image_url(user.info["banner"]),
- "background_image" => image_url(user.info["background"])
+ "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
+ "background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
+ "is_local" => user.local
}
if assigns[:token] do
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 11b36d6ac..09957e133 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -45,7 +45,8 @@ def represent_user(user) do
{:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
{:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
{:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
- {:Link, %{rel: "self", type: "application/activity+json", href: user.ap_id}}
+ {:Link, %{rel: "self", type: "application/activity+json", href: user.ap_id}},
+ {:Link, %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
]
}
|> XmlBuilder.to_doc
@@ -69,11 +70,13 @@ defp webfinger_from_xml(doc) do
topic = XML.string_from_xpath(~s{//Link[@rel="http://schemas.google.com/g/2010#updates-from"]/@href}, doc)
subject = XML.string_from_xpath("//Subject", doc)
salmon = XML.string_from_xpath(~s{//Link[@rel="salmon"]/@href}, doc)
+ subscribe_address = XML.string_from_xpath(~s{//Link[@rel="http://ostatus.org/schema/1.0/subscribe"]/@template}, doc)
data = %{
"magic_key" => magic_key,
"topic" => topic,
"subject" => subject,
- "salmon" => salmon
+ "salmon" => salmon,
+ "subscribe_address" => subscribe_address
}
{:ok, data}
end
diff --git a/priv/static/emoji/blank.png b/priv/static/emoji/blank.png
new file mode 100644
index 000000000..175a1d412
Binary files /dev/null and b/priv/static/emoji/blank.png differ
diff --git a/priv/static/emoji/f_00b.png b/priv/static/emoji/f_00b.png
new file mode 100644
index 000000000..8c0f8b7e8
Binary files /dev/null and b/priv/static/emoji/f_00b.png differ
diff --git a/priv/static/emoji/f_00b11b.png b/priv/static/emoji/f_00b11b.png
new file mode 100644
index 000000000..408b8fdd3
Binary files /dev/null and b/priv/static/emoji/f_00b11b.png differ
diff --git a/priv/static/emoji/f_00b33b.png b/priv/static/emoji/f_00b33b.png
new file mode 100644
index 000000000..7926f497c
Binary files /dev/null and b/priv/static/emoji/f_00b33b.png differ
diff --git a/priv/static/emoji/f_00h.png b/priv/static/emoji/f_00h.png
new file mode 100644
index 000000000..a8e26b330
Binary files /dev/null and b/priv/static/emoji/f_00h.png differ
diff --git a/priv/static/emoji/f_00t.png b/priv/static/emoji/f_00t.png
new file mode 100644
index 000000000..5b78986f7
Binary files /dev/null and b/priv/static/emoji/f_00t.png differ
diff --git a/priv/static/emoji/f_01b.png b/priv/static/emoji/f_01b.png
new file mode 100644
index 000000000..13359359e
Binary files /dev/null and b/priv/static/emoji/f_01b.png differ
diff --git a/priv/static/emoji/f_03b.png b/priv/static/emoji/f_03b.png
new file mode 100644
index 000000000..ab95f9b28
Binary files /dev/null and b/priv/static/emoji/f_03b.png differ
diff --git a/priv/static/emoji/f_10b.png b/priv/static/emoji/f_10b.png
new file mode 100644
index 000000000..b57b5b3b2
Binary files /dev/null and b/priv/static/emoji/f_10b.png differ
diff --git a/priv/static/emoji/f_11b.png b/priv/static/emoji/f_11b.png
new file mode 100644
index 000000000..dcdb61ea4
Binary files /dev/null and b/priv/static/emoji/f_11b.png differ
diff --git a/priv/static/emoji/f_11b00b.png b/priv/static/emoji/f_11b00b.png
new file mode 100644
index 000000000..48e487dff
Binary files /dev/null and b/priv/static/emoji/f_11b00b.png differ
diff --git a/priv/static/emoji/f_11b22b.png b/priv/static/emoji/f_11b22b.png
new file mode 100644
index 000000000..a1f09b063
Binary files /dev/null and b/priv/static/emoji/f_11b22b.png differ
diff --git a/priv/static/emoji/f_11h.png b/priv/static/emoji/f_11h.png
new file mode 100644
index 000000000..59a86c98e
Binary files /dev/null and b/priv/static/emoji/f_11h.png differ
diff --git a/priv/static/emoji/f_11t.png b/priv/static/emoji/f_11t.png
new file mode 100644
index 000000000..8a31379b1
Binary files /dev/null and b/priv/static/emoji/f_11t.png differ
diff --git a/priv/static/emoji/f_12b.png b/priv/static/emoji/f_12b.png
new file mode 100644
index 000000000..99481725e
Binary files /dev/null and b/priv/static/emoji/f_12b.png differ
diff --git a/priv/static/emoji/f_21b.png b/priv/static/emoji/f_21b.png
new file mode 100644
index 000000000..d6f6e2131
Binary files /dev/null and b/priv/static/emoji/f_21b.png differ
diff --git a/priv/static/emoji/f_22b.png b/priv/static/emoji/f_22b.png
new file mode 100644
index 000000000..e90a407d9
Binary files /dev/null and b/priv/static/emoji/f_22b.png differ
diff --git a/priv/static/emoji/f_22b11b.png b/priv/static/emoji/f_22b11b.png
new file mode 100644
index 000000000..ca25cf1af
Binary files /dev/null and b/priv/static/emoji/f_22b11b.png differ
diff --git a/priv/static/emoji/f_22b33b.png b/priv/static/emoji/f_22b33b.png
new file mode 100644
index 000000000..ec4760ca1
Binary files /dev/null and b/priv/static/emoji/f_22b33b.png differ
diff --git a/priv/static/emoji/f_22h.png b/priv/static/emoji/f_22h.png
new file mode 100644
index 000000000..c82c9179b
Binary files /dev/null and b/priv/static/emoji/f_22h.png differ
diff --git a/priv/static/emoji/f_22t.png b/priv/static/emoji/f_22t.png
new file mode 100644
index 000000000..2a858a6f3
Binary files /dev/null and b/priv/static/emoji/f_22t.png differ
diff --git a/priv/static/emoji/f_23b.png b/priv/static/emoji/f_23b.png
new file mode 100644
index 000000000..551598a24
Binary files /dev/null and b/priv/static/emoji/f_23b.png differ
diff --git a/priv/static/emoji/f_30b.png b/priv/static/emoji/f_30b.png
new file mode 100644
index 000000000..f2cb32978
Binary files /dev/null and b/priv/static/emoji/f_30b.png differ
diff --git a/priv/static/emoji/f_32b.png b/priv/static/emoji/f_32b.png
new file mode 100644
index 000000000..5646a0fcd
Binary files /dev/null and b/priv/static/emoji/f_32b.png differ
diff --git a/priv/static/emoji/f_33b.png b/priv/static/emoji/f_33b.png
new file mode 100644
index 000000000..86f2a0a0e
Binary files /dev/null and b/priv/static/emoji/f_33b.png differ
diff --git a/priv/static/emoji/f_33b00b.png b/priv/static/emoji/f_33b00b.png
new file mode 100644
index 000000000..9f9a750b0
Binary files /dev/null and b/priv/static/emoji/f_33b00b.png differ
diff --git a/priv/static/emoji/f_33b22b.png b/priv/static/emoji/f_33b22b.png
new file mode 100644
index 000000000..48520a17e
Binary files /dev/null and b/priv/static/emoji/f_33b22b.png differ
diff --git a/priv/static/emoji/f_33h.png b/priv/static/emoji/f_33h.png
new file mode 100644
index 000000000..0b8a333d2
Binary files /dev/null and b/priv/static/emoji/f_33h.png differ
diff --git a/priv/static/emoji/f_33t.png b/priv/static/emoji/f_33t.png
new file mode 100644
index 000000000..0f8812075
Binary files /dev/null and b/priv/static/emoji/f_33t.png differ
diff --git a/priv/static/images/avi.png b/priv/static/images/avi.png
new file mode 100644
index 000000000..336fd15ef
Binary files /dev/null and b/priv/static/images/avi.png differ
diff --git a/priv/static/images/banner.png b/priv/static/images/banner.png
new file mode 100644
index 000000000..467c075d6
Binary files /dev/null and b/priv/static/images/banner.png differ
diff --git a/priv/static/index.html b/priv/static/index.html
index ba514c0f4..8571fa719 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/instance/thumbnail.jpeg b/priv/static/instance/thumbnail.jpeg
new file mode 100644
index 000000000..b7e012644
Binary files /dev/null and b/priv/static/instance/thumbnail.jpeg differ
diff --git a/priv/static/static/config.json b/priv/static/static/config.json
index 263107cea..8e4b21cad 100644
--- a/priv/static/static/config.json
+++ b/priv/static/static/config.json
@@ -1,7 +1,7 @@
{
- "name": "Pleroma FE",
"theme": "pleroma-dark",
"background": "/static/bg.jpg",
"logo": "/static/logo.png",
- "registrationOpen": true
+ "defaultPath": "/main/all",
+ "chatDisabled": false
}
diff --git a/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css b/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css
deleted file mode 100644
index b629d42b1..000000000
Binary files a/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css and /dev/null differ
diff --git a/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css.map b/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css.map
deleted file mode 100644
index 6e32f2ca8..000000000
--- a/priv/static/static/css/app.67f64792f89a96e59442c437c7ded0b3.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["webpack:///webpack:///src/App.scss","webpack:///webpack:///src/components/login_form/login_form.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/nav_panel/nav_panel.vue","webpack:///webpack:///src/components/notifications/notifications.scss","webpack:///webpack:///src/components/status/status.vue","webpack:///webpack:///src/components/attachment/attachment.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/user_finder/user_finder.vue","webpack:///webpack:///src/components/timeline/timeline.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/style_switcher/style_switcher.vue","webpack:///webpack:///src/components/registration/registration.vue","webpack:///webpack:///src/components/user_settings/user_settings.vue","webpack:///webpack:///src/components/chat/chat.vue"],"names":[],"mappings":"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","file":"static/css/app.67f64792f89a96e59442c437c7ded0b3.css","sourcesContent":["\n#app{background-size:cover;background-attachment:fixed;background-repeat:no-repeat;background-position:0 50px;min-height:100vh\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-size:14px;margin:0\n}\na{text-decoration:none\n}\nbutton{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:none;border-radius:5px;cursor:pointer;border-top:1px solid rgba(255,255,255,0.2);border-bottom:1px solid rgba(0,0,0,0.2);box-shadow:0px 0px 2px black;font-size:14px;font-family:sans-serif\n}\nbutton:hover{box-shadow:0px 0px 4px rgba(255,255,255,0.3)\n}\nbutton:disabled{cursor:not-allowed;opacity:0.5\n}\n.container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0 10px 0 10px\n}\n.gaps{margin:-1em 0 0 -1em\n}\n.item{-ms-flex:1;flex:1;line-height:21px;height:21px;overflow:hidden\n}\n.item .nav-icon{font-size:1.1em;margin-left:0.4em\n}\n.gaps>.item{padding:1em 0 0 1em\n}\n.auto-size{-ms-flex:1;flex:1\n}\nnav{width:100%;-ms-flex-align:center;align-items:center;position:fixed;height:50px\n}\nnav .inner-nav{padding-left:20px;padding-right:20px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-preferred-size:970px;flex-basis:970px;margin:auto;height:50px;background-repeat:no-repeat;background-position:center;background-size:contain\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;-ms-flex-direction:column;flex-direction:column;margin:0.5em;border-radius:10px;box-shadow:1px 1px 4px rgba(0,0,0,0.6);overflow:hidden\n}\n.panel-body:empty::before{content:\"¯\\\\_(ツ)_/¯\";display:block;margin:1em;text-align:center\n}\n.panel-heading{border-radius:10px 10px 0 0;background-size:cover;padding:0.6em 1.0em;text-align:left;font-size:1.3em;line-height:24px\n}\n.panel-footer{border-radius:0 0 10px 10px\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;box-shadow:0px 0px 4px rgba(0,0,0,0.6)\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}\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@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 0 0 0\n}\n.panel{margin:0.5em 0 0.5em 0\n}\n}\n.item.right{text-align:right;padding-right:20px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/App.scss","\n.login-form input{border-width:1px;border-style:solid;border-color:silver;border-radius:5px;padding:0.1em 0.2em 0.2em 0.2em\n}\n.login-form .btn{min-height:28px;width:10em\n}\n.login-form .error{border-radius:5px;text-align:center;background-color:rgba(255,48,16,0.65);min-height:28px;line-height:28px\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.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:50%\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 .error,.login .error{border-radius:5px;text-align:center;background-color:rgba(255,48,16,0.65);padding:0.25em;margin:0.35em;display:-ms-flexbox;display:flex\n}\n.post-status-form .attachments,.login .attachments{padding:0 0.5em\n}\n.post-status-form .attachments .attachment,.login .attachments .attachment{position:relative;margin:0.5em 0.8em 0.2em 0\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:5px;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 .icon-cancel,.login .icon-cancel{cursor:pointer\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,.login form textarea{border:solid;border-width:1px;border-color:inherit;border-radius:5px;line-height:16px;padding:5px;resize:none;overflow:hidden\n}\n.post-status-form form textarea:focus,.login form textarea: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;position:absolute;z-index:1;box-shadow:1px 2px 4px rgba(0,0,0,0.5);min-width:75%\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:2px;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{font-style:italic\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\n}\n.profile-panel-background .panel-heading{padding:0.6em 0em;text-align:center\n}\n.profile-panel-body{top:-0em;padding-top:4em;word-wrap:break-word\n}\n.user-info{color:white;padding:0 16px 16px 16px;margin-bottom:-4em;text-shadow:0px 1px 1.5px #000\n}\n.user-info .usersettings{color:white;opacity:0.8\n}\n.user-info .container{padding:16px 10px 4px 10px;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-direction:column;flex-direction:column;-ms-flex-line-pack:start;align-content:flex-start;-ms-flex-pack:center;justify-content:center;max-height:56px;overflow:hidden\n}\n.user-info img{border-radius:5px;-ms-flex:1 0 100%;flex:1 0 100%;width:56px;height:56px;box-shadow:0px 1px 8px rgba(0,0,0,0.75);object-fit:cover\n}\n.user-info .name-and-screen-name{display:block;margin-left:0.6em;text-align:left;text-overflow:ellipsis;white-space:nowrap\n}\n.user-info .user-name{color:white\n}\n.user-info .user-screen-name{color:white;font-weight:lighter;font-size:15px;padding-right:0.1em;-ms-flex:0 0 auto;flex:0 0 auto\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-top:0.7em;margin-bottom:-1.0em\n}\n.user-info .user-interactions div{-ms-flex:1;flex:1\n}\n.user-info .user-interactions .following{color:white;font-size:14px;-ms-flex:0 0 100%;flex:0 0 100%;margin:-0.7em 0.0em 0.3em 0.0em;padding-left:16px;text-align:left\n}\n.user-info .user-interactions .mute{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:92%;height:100%\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:1em 1.5em 0em 1em;text-align:center\n}\n.user-count{-ms-flex:1;flex:1\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{font-size:0.8em;opacity:0.5\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card_content/user_card_content.vue","\n.nav-panel ul{list-style:none;margin:0;padding:0\n}\n.nav-panel li{border-bottom:1px solid;border-color:inherit;padding:0\n}\n.nav-panel li:first-child a{border-top-right-radius:10px;border-top-left-radius:10px\n}\n.nav-panel li:last-child a{border-bottom-right-radius:10px;border-bottom-left-radius: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:transparent\n}\n.nav-panel a.router-link-active{font-weight:bolder;background-color:transparent\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.notifications{padding-bottom:15em\n}\n.notifications .panel-heading{position:relative\n}\n.notifications .panel-heading .read-button{position:absolute;right:0.7em;height:1.8em;line-height:100%\n}\n.notifications .unseen-count{display:inline-block;background-color:rgba(255,16,8,0.8);text-shadow:0px 0px 3px rgba(0,0,0,0.5);min-width:1.3em;border-radius:1.3em;margin:0 0.2em 0 -0.4em;color:white;font-size:0.9em;text-align:center;line-height:1.3em\n}\n.notifications .notification{padding:0.4em 0 0 10px;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-bottom-color:inherit\n}\n.notifications .notification .text{min-width:0px;word-wrap:break-word;line-height:18px;position:relative;overflow:hidden;padding:0.3em 0.8em 0.5em\n}\n.notifications .notification .text .icon-retweet.lit{color:#0fa00f\n}\n.notifications .notification .text .icon-user-plus.lit{color:#0095ff\n}\n.notifications .notification .text .icon-reply.lit{color:#0095ff\n}\n.notifications .notification .text .icon-star.lit{color:orange\n}\n.notifications .notification .text .status-content{margin:0;max-height:300px\n}\n.notifications .notification .text h1{word-break:break-all;margin:0 0 0.3em;padding:0;font-size:1em;line-height:20px\n}\n.notifications .notification .text h1 small{font-weight:lighter\n}\n.notifications .notification .text p{margin:0;margin-top:0;margin-bottom:0.3em\n}\n.notifications .notification .avatar{padding-top:0.3em;width:32px;height:32px;border-radius:50%\n}\n.notifications .notification:last-child{border-bottom:none;border-radius:0 0 10px 10px\n}\n.notifications .notification-content{max-height:12em;overflow-y:hidden\n}\n.notifications .notification-gradient{position:absolute;width:100%;height:4em;margin-top:8em\n}\n.notifications .unseen{border-left:4px solid rgba(255,16,8,0.75);padding-left:6px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/notifications/notifications.scss","\nstatus-text-container{display:block\n}\n.status-preview{position:absolute;max-width:34em;padding:0.5em;display:-ms-flexbox;display:flex;border-color:inherit;border-style:solid;border-width:1px;border-radius:4px;box-shadow:2px 2px 3px rgba(0,0,0,0.5);margin-top:0.5em;margin-left:1em\n}\n.status-preview .avatar{-ms-flex-negative:0;flex-shrink:0;width:32px;height:32px;border-radius:50%\n}\n.status-preview .text{padding:0 0.5em 0.5em 0.5em\n}\n.status-preview .text h4{margin-bottom:0.4em\n}\n.status-preview .text h4 small{font-weight:lighter\n}\n.status-preview-loading{display:block;font-size:2em;min-width:8em;text-align:center\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\n}\n.timeline .status-el{border-bottom-width:1px;border-bottom-style:solid\n}\n.status-el .notify .avatar{border-width:3px;border-style:solid\n}\n.status-el .media-body{-ms-flex:1;flex:1;padding-left:0.5em\n}\n.status-el .user-content{min-height:52px;padding-top:1px\n}\n.status-el .media-heading{display:-ms-flexbox;display:flex;min-height:1.4em;margin-bottom:0.3em\n}\n.status-el .media-heading small{font-weight:lighter\n}\n.status-el .media-heading h4{margin-right:0.4em\n}\n.status-el .media-heading .name-and-links{-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.status-el .media-heading .replies{-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.status-el .expand{margin-right:-0.3em\n}\n.status-el a{display:inline-block;word-break:break-all\n}\n.status-el .status-content{margin:3px 15px 4px 0;max-height:400px;overflow-y:auto;overflow-x:hidden\n}\n.status-el .status-content img,.status-el .status-content video{max-width:100%;max-height:400px;object-fit:contain\n}\n.status-el .status-content blockquote{margin:0.2em 0 0.2em 2em;font-style:italic\n}\n.status-el p{margin:0;margin-top:0.2em;margin-bottom:0.5em\n}\n.status-el .media-left{margin:0.2em 0.3em 0 0\n}\n.status-el .media-left img{float:right;border-radius:5px\n}\n.status-el .retweet-info{padding:0.7em 0 0 0.6em\n}\n.status-el .retweet-info .media-left{display:-ms-flexbox;display:flex\n}\n.status-el .retweet-info .media-left i{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center;text-align:right;-ms-flex:1;flex:1;padding-right:0.3em\n}\n.status-fadein{animation-duration:0.5s;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{padding-top:0.15em;width:100%;display:-ms-flexbox;display:flex\n}\n.status-actions div,.status-actions favorite-button{max-width:6em;-ms-flex:1;flex:1\n}\n.icon-reply:hover{color:#0095ff\n}\n.icon-reply.icon-reply-active{color:#0095ff\n}\n.status .avatar{width:48px;height:48px\n}\n.status .avatar.retweeted{width:40px;height:40px;margin-right:8px;margin-bottom:8px\n}\n.status img.avatar-retweeter{width:24px;height:24px;position:absolute;margin-left:24px;margin-top:24px\n}\n.status.compact .avatar{width:32px\n}\n.status{padding:0.4em 0.7em 0.45em 0.7em;border-left:4px rgba(255,48,16,0.65);border-left-style:inherit\n}\n.status-conversation:last-child{border-bottom:none\n}\n.timeline .panel.timeline{border-radius:10px;overflow:hidden\n}\n.muted{padding:0.1em 0.4em 0.1em 0.8em\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@media all and (max-width: 960px){\n.status-el .name-and-links{margin-left:-0.25em\n}\n.status{max-width:100%\n}\n.status .avatar{width:40px;height:40px\n}\n.status .avatar.retweeted{width:34px;height:34px;margin-right:8px;margin-bottom:8px\n}\n.status img.avatar-retweeter{width:22px;height:22px;position:absolute;margin-left:18px;margin-top:18px\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;margin-right:-0.7em\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 .attachment{-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;border-style:solid;border-width:1px;border-radius:5px;overflow:hidden\n}\n.attachments .attachment.video{line-height:0\n}\n.attachments .attachment.html{-ms-flex-preferred-size:90%;flex-basis:90%;width:100%;display:-ms-flexbox;display:flex\n}\n.attachments .attachment.loading{cursor:progress\n}\n.attachments .attachment .hider{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);font-weight:bold;z-index:4\n}\n.attachments .attachment video{max-height:500px;height:100%;width:100%;z-index:0\n}\n.attachments .attachment audio{width:100%\n}\n.attachments .attachment img.media-upload{margin-bottom:-2px;max-height:300px;max-width:100%\n}\n.attachments .attachment .oembed{width:100%;margin-right:15px;display:-ms-flexbox;display:flex\n}\n.attachments .attachment .oembed img{width:100%\n}\n.attachments .attachment .oembed .image{-ms-flex:1;flex:1\n}\n.attachments .attachment .oembed .image img{border:0px;border-radius:5px;height:100%;object-fit:cover\n}\n.attachments .attachment .oembed .text{-ms-flex:2;flex:2;margin:8px;word-break:break-all\n}\n.attachments .attachment .oembed .text h1{font-size:14px;margin:0px\n}\n.attachments .attachment a.image-attachment{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1\n}\n.attachments .attachment a.image-attachment img{object-fit:contain;width:100%;height:100%;max-height:500px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/attachment/attachment.vue","\n.favorite-button{cursor:pointer;animation-duration:0.6s\n}\n.favorite-button:hover{color:orange\n}\n.favorite-button.icon-star{color:orange\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/favorite_button/favorite_button.vue","\n.icon-retweet{cursor:pointer;animation-duration:0.6s\n}\n.icon-retweet:hover{color:#0fa00f\n}\n.icon-retweet.retweeted{color:#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\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/delete_button/delete_button.vue","\n.user-finder-container{height:21px;max-width:100%\n}\n.user-finder-input{border-width:1px;border-style:solid;border-color:inherit;border-radius:5px;max-width:80%;padding:0.1em 0.2em 0.2em 0.2em\n}\n.finder-error{background-color:rgba(255,48,16,0.65);margin:0.35em;border-radius:5px;padding:0.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_finder/user_finder.vue","\n.timeline .timeline-heading{position:relative;display:-ms-flexbox;display:flex\n}\n.timeline .title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:70%\n}\n.timeline .loadmore-button{position:absolute;right:0.6em;font-size:14px;min-width:6em;height:1.8em;line-height:100%\n}\n.timeline .loadmore-text{position:absolute;right:0.6em;font-size:14px;min-width:6em;border-radius:5px;font-family:sans-serif;text-align:center;padding:0 0.5em 0 0.5em;opacity:0.8\n}\n.timeline .error{background-color:rgba(255,48,16,0.65)\n}\n.new-status-notification{position:relative;margin-top:-1px;font-size:1.1em;border-width:1px 0 0 0;border-style:solid;border-radius:0 0 10px 10px;padding:10px;z-index:1\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/timeline/timeline.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;margin-right:2em;text-align:left;width:100%\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:inherit\n}\n.card .avatar{margin-top:0.2em;width:32px;height:32px;border-radius:50%\n}\n.usercard{width:-webkit-fill-available;width:-moz-webkit-fill-available;stretch:fill;margin:0.2em 0 0.7em 0;border-radius:10px;border-style:solid;border-color:inherit;border-width:1px;overflow:hidden\n}\n.usercard p{margin-bottom:0\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;padding-bottom:10px;border-radius:10px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_profile/user_profile.vue","\n.setting-item{margin:1em 1em 1.4em\n}\n.setting-item textarea{width:100%;height:100px\n}\n.setting-item .old-avatar{width:128px;border-radius:5px\n}\n.setting-item .new-avatar{object-fit:cover;width:128px;height:128px;border-radius:5px\n}\n.setting-item .btn{margin-top:1em;min-height:28px;width:10em\n}\n.setting-list{list-style-type:none\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/settings/settings.vue","\n.style-switcher{margin-right:1em\n}\n.color-container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.color-item{max-width:9em;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.theme-color-in{max-width:8em;border-radius:2px;border:0;padding:5px;margin:5px 0 5px 0\n}\n.theme-preview-content{padding:20px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/style_switcher/style_switcher.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\n}\n.registration-form form textarea{border:solid;border-width:1px;border-color:silver;border-radius:5px;line-height:16px;padding:5px;resize:vertical\n}\n.registration-form input{border-width:1px;border-style:solid;border-color:silver;border-radius:5px;padding:0.1em 0.2em 0.2em 0.2em\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{border-radius:5px;text-align:center;margin:0.5em 0.6em 0;background-color:rgba(255,48,16,0.65);min-height:28px;line-height:28px\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 .name-changer{border-width:1px;border-style:solid;border-radius:5px;padding:0.2em 0.2em 0.2em 0.2em\n}\n.profile-edit .name-submit{padding:0.2em 0.5em 0.2em 0.5em\n}\n.profile-edit .bio{border-width:1px;border-style:solid;border-radius:5px;margin:0\n}\n.profile-edit .banner{max-width:400px;border-radius:5px\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.chat-message{padding:0.2em 0.5em\n}\n.chat-avatar img{height:32px;width:32px;border-radius:5px;margin-right:0.5em\n}\n.chat-input{display:-ms-flexbox;display:flex\n}\n.chat-input form{-ms-flex:auto;flex:auto\n}\n.chat-input form input{margin:0.5em;width:100%\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/chat/chat.vue"],"sourceRoot":""}
\ No newline at end of file
diff --git a/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css b/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css
new file mode 100644
index 000000000..6aebbb3ba
Binary files /dev/null and b/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css differ
diff --git a/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css.map b/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css.map
new file mode 100644
index 000000000..930c703e6
--- /dev/null
+++ b/priv/static/static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack:///src/App.scss","webpack:///webpack:///src/components/login_form/login_form.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/nav_panel/nav_panel.vue","webpack:///webpack:///src/components/notifications/notifications.scss","webpack:///webpack:///src/components/status/status.vue","webpack:///webpack:///src/components/attachment/attachment.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/user_finder/user_finder.vue","webpack:///webpack:///src/components/chat_panel/chat_panel.vue","webpack:///webpack:///src/components/timeline/timeline.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/style_switcher/style_switcher.vue","webpack:///webpack:///src/components/registration/registration.vue","webpack:///webpack:///src/components/user_settings/user_settings.vue"],"names":[],"mappings":"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","file":"static/css/app.b3deb1dd44970d86cc6b368f36fd09d9.css","sourcesContent":["\n#app{background-size:cover;background-attachment:fixed;background-repeat:no-repeat;background-position:0 50px;min-height:100vh\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-size:14px;margin:0\n}\na{text-decoration:none\n}\nbutton{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:none;border-radius:5px;cursor:pointer;border-top:1px solid rgba(255,255,255,0.2);border-bottom:1px solid rgba(0,0,0,0.2);box-shadow:0px 0px 2px black;font-size:14px;font-family:sans-serif\n}\nbutton:hover{box-shadow:0px 0px 4px rgba(255,255,255,0.3)\n}\nbutton:disabled{cursor:not-allowed;opacity:0.5\n}\n.container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0 10px 0 10px\n}\n.gaps{margin:-1em 0 0 -1em\n}\n.item{-ms-flex:1;flex:1;line-height:21px;height:21px;overflow:hidden\n}\n.item .nav-icon{font-size:1.1em;margin-left:0.4em\n}\n.gaps>.item{padding:1em 0 0 1em\n}\n.auto-size{-ms-flex:1;flex:1\n}\nnav{width:100%;-ms-flex-align:center;align-items:center;position:fixed;height:50px\n}\nnav .inner-nav{padding-left:20px;padding-right:20px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-preferred-size:970px;flex-basis:970px;margin:auto;height:50px;background-repeat:no-repeat;background-position:center;background-size:contain\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;-ms-flex-direction:column;flex-direction:column;margin:0.5em;border-radius:10px;box-shadow:1px 1px 4px rgba(0,0,0,0.6);overflow:hidden\n}\n.panel-body:empty::before{content:\"¯\\\\_(ツ)_/¯\";display:block;margin:1em;text-align:center\n}\n.panel-heading{border-radius:10px 10px 0 0;background-size:cover;padding:0.6em 1.0em;text-align:left;font-size:1.3em;line-height:24px\n}\n.panel-footer{border-radius:0 0 10px 10px\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;box-shadow:0px 0px 4px rgba(0,0,0,0.6)\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}\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@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 0 0 0\n}\n.panel{margin:0.5em 0 0.5em 0\n}\n}\n.item.right{text-align:right;padding-right:20px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/App.scss","\n.login-form input{border-width:1px;border-style:solid;border-color:silver;border-radius:5px;padding:0.1em 0.2em 0.2em 0.2em\n}\n.login-form .btn{min-height:28px;width:10em\n}\n.login-form .error{border-radius:5px;text-align:center;background-color:rgba(255,48,16,0.65);min-height:28px;line-height:28px\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.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:50%\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{border-radius:5px;text-align:center;background-color:rgba(255,48,16,0.65);padding:0.25em;margin:0.35em;display:-ms-flexbox;display:flex\n}\n.post-status-form .attachments,.login .attachments{padding:0 0.5em\n}\n.post-status-form .attachments .attachment,.login .attachments .attachment{position:relative;margin:0.5em 0.8em 0.2em 0\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:5px;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 .icon-cancel,.login .icon-cancel{cursor:pointer\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,.login form textarea{border:solid;border-width:1px;border-color:inherit;border-radius:5px;line-height:16px;padding:5px;resize:none;overflow:hidden\n}\n.post-status-form form textarea:focus,.login form textarea: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;position:absolute;z-index:1;box-shadow:1px 2px 4px rgba(0,0,0,0.5);min-width:75%\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:2px;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{font-style:italic\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\n}\n.profile-panel-background .panel-heading{padding:0.6em 0em;text-align:center\n}\n.profile-panel-body{top:-0em;padding-top:4em;word-wrap:break-word\n}\n.user-info{color:white;padding:0 16px 16px 16px;margin-bottom:-4em;text-shadow:0px 1px 1.5px #000\n}\n.user-info .usersettings{color:white;opacity:0.8\n}\n.user-info .container{padding:16px 10px 4px 10px;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-direction:column;flex-direction:column;-ms-flex-line-pack:start;align-content:flex-start;-ms-flex-pack:center;justify-content:center;max-height:56px;overflow:hidden\n}\n.user-info img{border-radius:5px;-ms-flex:1 0 100%;flex:1 0 100%;width:56px;height:56px;box-shadow:0px 1px 8px rgba(0,0,0,0.75);object-fit:cover\n}\n.user-info .name-and-screen-name{display:block;margin-left:0.6em;text-align:left;text-overflow:ellipsis;white-space:nowrap\n}\n.user-info .user-name{color:white\n}\n.user-info .user-screen-name{color:white;font-weight:lighter;font-size:15px;padding-right:0.1em;-ms-flex:0 0 auto;flex:0 0 auto\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-top:0.7em;margin-bottom:-1.0em\n}\n.user-info .user-interactions div{-ms-flex:1;flex:1\n}\n.user-info .user-interactions .following{color:white;font-size:14px;-ms-flex:0 0 100%;flex:0 0 100%;margin:-0.7em 0.0em 0.3em 0.0em;padding-left:16px;text-align:left\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:92%;height:100%\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:1em 1.5em 0em 1em;text-align:center\n}\n.user-count{-ms-flex:1;flex:1\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{font-size:0.8em;opacity:0.5\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_card_content/user_card_content.vue","\n.nav-panel ul{list-style:none;margin:0;padding:0\n}\n.nav-panel li{border-bottom:1px solid;border-color:inherit;padding:0\n}\n.nav-panel li:first-child a{border-top-right-radius:10px;border-top-left-radius:10px\n}\n.nav-panel li:last-child a{border-bottom-right-radius:10px;border-bottom-left-radius: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:transparent\n}\n.nav-panel a.router-link-active{font-weight:bolder;background-color:transparent\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.notifications{padding-bottom:15em\n}\n.notifications .panel-heading{position:relative\n}\n.notifications .panel-heading .read-button{position:absolute;right:0.7em;height:1.8em;line-height:100%\n}\n.notifications .unseen-count{display:inline-block;background-color:rgba(255,16,8,0.8);text-shadow:0px 0px 3px rgba(0,0,0,0.5);min-width:1.3em;border-radius:1.3em;margin:0 0.2em 0 -0.4em;color:white;font-size:0.9em;text-align:center;line-height:1.3em\n}\n.notifications .notification{padding:0.4em 0 0 10px;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-bottom-color:inherit\n}\n.notifications .notification .text{min-width:0px;word-wrap:break-word;line-height:18px;position:relative;overflow:hidden;padding:0.3em 0.8em 0.5em\n}\n.notifications .notification .text .icon-retweet.lit{color:#0fa00f\n}\n.notifications .notification .text .icon-user-plus.lit{color:#0095ff\n}\n.notifications .notification .text .icon-reply.lit{color:#0095ff\n}\n.notifications .notification .text .icon-star.lit{color:orange\n}\n.notifications .notification .text .status-content{margin:0;max-height:300px\n}\n.notifications .notification .text h1{word-break:break-all;margin:0 0 0.3em;padding:0;font-size:1em;line-height:20px\n}\n.notifications .notification .text h1 small{font-weight:lighter\n}\n.notifications .notification .text p{margin:0;margin-top:0;margin-bottom:0.3em\n}\n.notifications .notification .avatar{padding-top:0.3em;width:32px;height:32px;border-radius:50%\n}\n.notifications .notification:last-child{border-bottom:none;border-radius:0 0 10px 10px\n}\n.notifications .notification-content{max-height:12em;overflow-y:hidden\n}\n.notifications .notification-gradient{position:absolute;width:100%;height:4em;margin-top:8em\n}\n.notifications .unseen{border-left:4px solid rgba(255,16,8,0.75);padding-left:6px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/notifications/notifications.scss","\nstatus-text-container{display:block\n}\n.status-preview{position:absolute;max-width:34em;padding:0.5em;display:-ms-flexbox;display:flex;border-color:inherit;border-style:solid;border-width:1px;border-radius:4px;box-shadow:2px 2px 3px rgba(0,0,0,0.5);margin-top:0.5em;margin-left:1em\n}\n.status-preview .avatar{-ms-flex-negative:0;flex-shrink:0;width:32px;height:32px;border-radius:50%\n}\n.status-preview .text{padding:0 0.5em 0.5em 0.5em\n}\n.status-preview .text h4{margin-bottom:0.4em\n}\n.status-preview .text h4 small{font-weight:lighter\n}\n.status-preview-loading{display:block;font-size:2em;min-width:8em;text-align:center\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\n}\n.timeline .status-el{border-bottom-width:1px;border-bottom-style:solid\n}\n.status-el .notify .avatar{border-width:3px;border-style:solid\n}\n.status-el .media-body{-ms-flex:1;flex:1;padding-left:0.5em\n}\n.status-el .user-content{min-height:52px;padding-top:1px\n}\n.status-el .media-heading{display:-ms-flexbox;display:flex;min-height:1.4em;margin-bottom:0.3em\n}\n.status-el .media-heading small{font-weight:lighter\n}\n.status-el .media-heading h4{margin-right:0.4em\n}\n.status-el .media-heading .name-and-links{-ms-flex:1 0;flex:1 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap\n}\n.status-el .media-heading .replies{-ms-flex-preferred-size:100%;flex-basis:100%\n}\n.status-el .expand{margin-right:-0.3em\n}\n.status-el a{display:inline-block;word-break:break-all\n}\n.status-el .status-content{margin:3px 15px 4px 0;max-height:400px;overflow-y:auto;overflow-x:hidden\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 p{margin:0;margin-top:0.2em;margin-bottom:0.5em\n}\n.status-el .media-left{margin:0.2em 0.3em 0 0\n}\n.status-el .media-left img{float:right;border-radius:5px\n}\n.status-el .retweet-info{padding:0.7em 0 0 0.6em\n}\n.status-el .retweet-info .media-left{display:-ms-flexbox;display:flex\n}\n.status-el .retweet-info .media-left i{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center;text-align:right;-ms-flex:1;flex:1;padding-right:0.3em\n}\n.status-fadein{animation-duration:0.5s;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{padding-top:0.15em;width:100%;display:-ms-flexbox;display:flex\n}\n.status-actions div,.status-actions favorite-button{max-width:6em;-ms-flex:1;flex:1\n}\n.icon-reply:hover{color:#0095ff\n}\n.icon-reply.icon-reply-active{color:#0095ff\n}\n.status .avatar{width:48px;height:48px\n}\n.status .avatar.retweeted{width:40px;height:40px;margin-right:8px;margin-bottom:8px\n}\n.status img.avatar-retweeter{width:24px;height:24px;position:absolute;margin-left:24px;margin-top:24px\n}\n.status.compact .avatar{width:32px\n}\n.status{padding:0.4em 0.7em 0.45em 0.7em;border-left:4px rgba(255,48,16,0.65);border-left-style:inherit\n}\n.status-conversation:last-child{border-bottom:none\n}\n.timeline .panel.timeline{border-radius:10px;overflow:hidden\n}\n.muted{padding:0.1em 0.4em 0.1em 0.8em\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@media all and (max-width: 960px){\n.status-el .name-and-links{margin-left:-0.25em\n}\n.status{max-width:100%\n}\n.status .avatar{width:40px;height:40px\n}\n.status .avatar.retweeted{width:34px;height:34px;margin-right:8px;margin-bottom:8px\n}\n.status img.avatar-retweeter{width:22px;height:22px;position:absolute;margin-left:18px;margin-top:18px\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;margin-right:-0.7em\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 .attachment{-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;border-style:solid;border-width:1px;border-radius:5px;overflow:hidden\n}\n.attachments .attachment.video{line-height:0\n}\n.attachments .attachment.html{-ms-flex-preferred-size:90%;flex-basis:90%;width:100%;display:-ms-flexbox;display:flex\n}\n.attachments .attachment.loading{cursor:progress\n}\n.attachments .attachment .hider{position:absolute;margin:10px;padding:5px;background:rgba(230,230,230,0.6);font-weight:bold;z-index:4\n}\n.attachments .attachment video{max-height:500px;height:100%;width:100%;z-index:0\n}\n.attachments .attachment audio{width:100%\n}\n.attachments .attachment img.media-upload{margin-bottom:-2px;max-height:300px;max-width:100%\n}\n.attachments .attachment .oembed{width:100%;margin-right:15px;display:-ms-flexbox;display:flex\n}\n.attachments .attachment .oembed img{width:100%\n}\n.attachments .attachment .oembed .image{-ms-flex:1;flex:1\n}\n.attachments .attachment .oembed .image img{border:0px;border-radius:5px;height:100%;object-fit:cover\n}\n.attachments .attachment .oembed .text{-ms-flex:2;flex:2;margin:8px;word-break:break-all\n}\n.attachments .attachment .oembed .text h1{font-size:14px;margin:0px\n}\n.attachments .attachment a.image-attachment{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1\n}\n.attachments .attachment a.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.fav-active{cursor:pointer;animation-duration:0.6s\n}\n.fav-active:hover{color:orange\n}\n.favorite-button.icon-star{color: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\n}\n.icon-retweet.retweeted{color:#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\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/delete_button/delete_button.vue","\n.user-finder-container{height:21px;max-width:100%\n}\n.user-finder-input{border-width:1px;border-style:solid;border-color:inherit;border-radius:5px;max-width:80%;padding:0.1em 0.2em 0.2em 0.2em\n}\n.finder-error{background-color:rgba(255,48,16,0.65);margin:0.35em;border-radius:5px;padding:0.25em\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_finder/user_finder.vue","\n.chat-window{max-height:200px;overflow-y:auto;overflow-x:hidden\n}\n.chat-message{padding:0.2em 0.5em\n}\n.chat-avatar img{height:32px;width:32px;border-radius:5px;margin-right:0.5em\n}\n.chat-input{display:-ms-flexbox;display:flex\n}\n.chat-input form{-ms-flex:auto;flex:auto\n}\n.chat-input form input{margin:0.5em;width:-webkit-fill-available;width:-moz-available;width:fill-available\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/chat_panel/chat_panel.vue","\n.timeline .timeline-heading{position:relative;display:-ms-flexbox;display:flex\n}\n.timeline .title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:70%\n}\n.timeline .loadmore-button{position:absolute;right:0.6em;font-size:14px;min-width:6em;height:1.8em;line-height:100%\n}\n.timeline .loadmore-text{position:absolute;right:0.6em;font-size:14px;min-width:6em;border-radius:5px;font-family:sans-serif;text-align:center;padding:0 0.5em 0 0.5em;opacity:0.8\n}\n.timeline .error{background-color:rgba(255,48,16,0.65)\n}\n.new-status-notification{position:relative;margin-top:-1px;font-size:1.1em;border-width:1px 0 0 0;border-style:solid;border-radius:0 0 10px 10px;padding:10px;z-index:1\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/timeline/timeline.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;margin-right:2em;text-align:left;width:100%\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:inherit\n}\n.card .avatar{margin-top:0.2em;width:32px;height:32px;border-radius:50%\n}\n.usercard{width:-webkit-fill-available;width:-moz-available;width:fill-available;margin:0.2em 0 0.7em 0;border-radius:10px;border-style:solid;border-color:inherit;border-width:1px;overflow:hidden\n}\n.usercard p{margin-bottom:0\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;padding-bottom:10px;border-radius:10px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/user_profile/user_profile.vue","\n.setting-item{margin:1em 1em 1.4em\n}\n.setting-item textarea{width:100%;height:100px\n}\n.setting-item .old-avatar{width:128px;border-radius:5px\n}\n.setting-item .new-avatar{object-fit:cover;width:128px;height:128px;border-radius:5px\n}\n.setting-item .btn{margin-top:1em;min-height:28px;width:10em\n}\n.setting-list{list-style-type:none\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/settings/settings.vue","\n.style-switcher{margin-right:1em\n}\n.color-container{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:justify;justify-content:space-between\n}\n.color-item{min-width:20em;display:-ms-flexbox;display:flex;-ms-flex:1 1 0px;flex:1 1 0;-ms-flex-align:baseline;align-items:baseline;margin:5px 6px 5px 0\n}\n.theme-color-cl,.theme-color-in{margin-left:4px;border-radius:2px;border:0\n}\n.theme-color-in{padding:5px;min-width:4em;max-width:7em;-ms-flex:1;flex:1\n}\n.theme-color-lb{-ms-flex:2;flex:2;min-width:7em;max-width:10em\n}\n.theme-color-cl{padding:1px;max-width:8em;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch;height:100%;-ms-flex:0;flex:0;min-width:2em;cursor:pointer\n}\n.theme-preview-content{padding:20px\n}\n\n\n\n// WEBPACK FOOTER //\n// webpack:///src/components/style_switcher/style_switcher.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\n}\n.registration-form form textarea{border:solid;border-width:1px;border-color:silver;border-radius:5px;line-height:16px;padding:5px;resize:vertical\n}\n.registration-form input{border-width:1px;border-style:solid;border-color:silver;border-radius:5px;padding:0.1em 0.2em 0.2em 0.2em\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{border-radius:5px;text-align:center;margin:0.5em 0.6em 0;background-color:rgba(255,48,16,0.65);min-height:28px;line-height:28px\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 .name-changer{border-width:1px;border-style:solid;border-radius:5px;padding:0.2em 0.2em 0.2em 0.2em\n}\n.profile-edit .name-submit{padding:0.2em 0.5em 0.2em 0.5em\n}\n.profile-edit .bio{border-width:1px;border-style:solid;border-radius:5px;margin:0\n}\n.profile-edit .banner{max-width:400px;border-radius:5px\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"],"sourceRoot":""}
\ No newline at end of file
diff --git a/priv/static/static/emoji.json b/priv/static/static/emoji.json
new file mode 100644
index 000000000..0117bac1c
--- /dev/null
+++ b/priv/static/static/emoji.json
@@ -0,0 +1 @@
+{"womans_clothes": "\ud83d\udc5a", "cookie": "\ud83c\udf6a", "woman_with_headscarf": "\ud83e\uddd5", "no_smoking": "\ud83d\udead", "e-mail": "\ud83d\udce7", "regional_indicator_d": "\ud83c\udde9", "oncoming_bus": "\ud83d\ude8d", "knife": "\ud83d\udd2a", "person_getting_haircut": "\ud83d\udc87", "grimacing": "\ud83d\ude2c", "ophiuchus": "\u26ce", "regional_indicator_q": "\ud83c\uddf6", "thinking": "\ud83e\udd14", "signal_strength": "\ud83d\udcf6", "cactus": "\ud83c\udf35", "bullettrain_front": "\ud83d\ude85", "floppy_disk": "\ud83d\udcbe", "doughnut": "\ud83c\udf69", "tv": "\ud83d\udcfa", "1234": "\ud83d\udd22", "anguished": "\ud83d\ude27", "clock1030": "\ud83d\udd65", "u7533": "\ud83c\ude38", "speak_no_evil": "\ud83d\ude4a", "chart_with_upwards_trend": "\ud83d\udcc8", "trophy": "\ud83c\udfc6", "musical_score": "\ud83c\udfbc", "chestnut": "\ud83c\udf30", "clock1130": "\ud83d\udd66", "abcd": "\ud83d\udd21", "syringe": "\ud83d\udc89", "shrimp": "\ud83e\udd90", "pisces": "\u2653", "left_facing_fist": "\ud83e\udd1b", "bar_chart": "\ud83d\udcca", "eagle": "\ud83e\udd85", "woman": "\ud83d\udc69", "keycap_ten": "\ud83d\udd1f", "yellow_heart": "\ud83d\udc9b", "croissant": "\ud83e\udd50", "mosque": "\ud83d\udd4c", "rice_ball": "\ud83c\udf59", "volcano": "\ud83c\udf0b", "baggage_claim": "\ud83d\udec4", "family": "\ud83d\udc6a", "beetle": "\ud83d\udc1e", "older_adult": "\ud83e\uddd3", "clock830": "\ud83d\udd63", "bacon": "\ud83e\udd53", "sound": "\ud83d\udd09", "no_bicycles": "\ud83d\udeb3", "rewind": "\u23ea", "adult": "\ud83e\uddd1", "scream_cat": "\ud83d\ude40", "person_playing_water_polo": "\ud83e\udd3d", "blue_car": "\ud83d\ude99", "smiley": "\ud83d\ude03", "kaaba": "\ud83d\udd4b", "twisted_rightwards_arrows": "\ud83d\udd00", "last_quarter_moon": "\ud83c\udf17", "first_place": "\ud83e\udd47", "joy_cat": "\ud83d\ude39", "sleeping": "\ud83d\ude34", "basketball": "\ud83c\udfc0", "pray": "\ud83d\ude4f", "trumpet": "\ud83c\udfba", "purple_heart": "\ud83d\udc9c", "broken_heart": "\ud83d\udc94", "astonished": "\ud83d\ude32", "soccer": "\u26bd", "princess": "\ud83d\udc78", "ant": "\ud83d\udc1c", "pig": "\ud83d\udc37", "vhs": "\ud83d\udcfc", "scream": "\ud83d\ude31", "mouse": "\ud83d\udc2d", "field_hockey": "\ud83c\udfd1", "ab": "\ud83c\udd8e", "tokyo_tower": "\ud83d\uddfc", "girl": "\ud83d\udc67", "u55b6": "\ud83c\ude3a", "guard": "\ud83d\udc82", "regional_indicator_s": "\ud83c\uddf8", "tulip": "\ud83c\udf37", "capital_abcd": "\ud83d\udd20", "beginner": "\ud83d\udd30", "couplekiss": "\ud83d\udc8f", "u5408": "\ud83c\ude34", "black_medium_small_square": "\u25fe", "paperclip": "\ud83d\udcce", "hedgehog": "\ud83e\udd94", "musical_note": "\ud83c\udfb5", "pill": "\ud83d\udc8a", "blue_heart": "\ud83d\udc99", "mens": "\ud83d\udeb9", "third_place": "\ud83e\udd49", "stew": "\ud83c\udf72", "prince": "\ud83e\udd34", "mortar_board": "\ud83c\udf93", "clock6": "\ud83d\udd55", "beer": "\ud83c\udf7a", "person_tipping_hand": "\ud83d\udc81", "triangular_ruler": "\ud83d\udcd0", "regional_indicator_y": "\ud83c\uddfe", "person_facepalming": "\ud83e\udd26", "steam_locomotive": "\ud83d\ude82", "fire_engine": "\ud83d\ude92", "horse": "\ud83d\udc34", "ribbon": "\ud83c\udf80", "white_large_square": "\u2b1c", "smirk": "\ud83d\ude0f", "genie": "\ud83e\uddde", "tangerine": "\ud83c\udf4a", "cl": "\ud83c\udd91", "japanese_goblin": "\ud83d\udc7a", "regional_indicator_u": "\ud83c\uddfa", "ring": "\ud83d\udc8d", "roller_coaster": "\ud83c\udfa2", "100": "\ud83d\udcaf", "clock12": "\ud83d\udd5b", "two_hearts": "\ud83d\udc95", "anger": "\ud83d\udca2", "black_circle": "\u26ab", "revolving_hearts": "\ud83d\udc9e", "space_invader": "\ud83d\udc7e", "bell": "\ud83d\udd14", "point_up_2": "\ud83d\udc46", "person_mountain_biking": "\ud83d\udeb5", "flags": "\ud83c\udf8f", "pushpin": "\ud83d\udccc", "large_blue_diamond": "\ud83d\udd37", "fairy": "\ud83e\uddda", "european_post_office": "\ud83c\udfe4", "statue_of_liberty": "\ud83d\uddfd", "man": "\ud83d\udc68", "microphone": "\ud83c\udfa4", "inbox_tray": "\ud83d\udce5", "bath": "\ud83d\udec0", "person_gesturing_ok": "\ud83d\ude46", "clap": "\ud83d\udc4f", "confused": "\ud83d\ude15", "fortune_cookie": "\ud83e\udd60", "kissing_closed_eyes": "\ud83d\ude1a", "kissing_heart": "\ud83d\ude18", "tropical_fish": "\ud83d\udc20", "taco": "\ud83c\udf2e", "kimono": "\ud83d\udc58", "u7a7a": "\ud83c\ude33", "rat": "\ud83d\udc00", "taurus": "\u2649", "shopping_cart": "\ud83d\uded2", "womans_hat": "\ud83d\udc52", "blossom": "\ud83c\udf3c", "moyai": "\ud83d\uddff", "clock130": "\ud83d\udd5c", "telescope": "\ud83d\udd2d", "running_shirt_with_sash": "\ud83c\udfbd", "person_running": "\ud83c\udfc3", "dizzy": "\ud83d\udcab", "crescent_moon": "\ud83c\udf19", "boom": "\ud83d\udca5", "restroom": "\ud83d\udebb", "fist": "\u270a", "white_flower": "\ud83d\udcae", "clown": "\ud83e\udd21", "neutral_face": "\ud83d\ude10", "id": "\ud83c\udd94", "carrot": "\ud83e\udd55", "rice_scene": "\ud83c\udf91", "foggy": "\ud83c\udf01", "turtle": "\ud83d\udc22", "mailbox_with_mail": "\ud83d\udcec", "baseball": "\u26be", "grin": "\ud83d\ude01", "bathtub": "\ud83d\udec1", "feet": "\ud83d\udc3e", "small_red_triangle": "\ud83d\udd3a", "camel": "\ud83d\udc2b", "aquarius": "\u2652", "face_with_symbols_over_mouth": "\ud83e\udd2c", "handbag": "\ud83d\udc5c", "date": "\ud83d\udcc5", "nail_care": "\ud83d\udc85", "satellite": "\ud83d\udce1", "candy": "\ud83c\udf6c", "white_medium_small_square": "\u25fd", "clock930": "\ud83d\udd64", "fearful": "\ud83d\ude28", "fork_and_knife": "\ud83c\udf74", "person_wearing_turban": "\ud83d\udc73", "confounded": "\ud83d\ude16", "helicopter": "\ud83d\ude81", "arrow_double_down": "\u23ec", "convenience_store": "\ud83c\udfea", "ghost": "\ud83d\udc7b", "bus": "\ud83d\ude8c", "waning_gibbous_moon": "\ud83c\udf16", "bank": "\ud83c\udfe6", "department_store": "\ud83c\udfec", "hockey": "\ud83c\udfd2", "fingers_crossed": "\ud83e\udd1e", "blond_haired_person": "\ud83d\udc71", "mag": "\ud83d\udd0d", "cut_of_meat": "\ud83e\udd69", "wink": "\ud83d\ude09", "railway_car": "\ud83d\ude83", "face_vomiting": "\ud83e\udd2e", "star_struck": "\ud83e\udd29", "first_quarter_moon_with_face": "\ud83c\udf1b", "octagonal_sign": "\ud83d\uded1", "hospital": "\ud83c\udfe5", "monkey": "\ud83d\udc12", "curly_loop": "\u27b0", "avocado": "\ud83e\udd51", "earth_americas": "\ud83c\udf0e", "flashlight": "\ud83d\udd26", "8ball": "\ud83c\udfb1", "clock630": "\ud83d\udd61", "boar": "\ud83d\udc17", "birthday": "\ud83c\udf82", "crocodile": "\ud83d\udc0a", "confetti_ball": "\ud83c\udf8a", "door": "\ud83d\udeaa", "school_satchel": "\ud83c\udf92", "peanuts": "\ud83e\udd5c", "regional_indicator_m": "\ud83c\uddf2", "bust_in_silhouette": "\ud83d\udc64", "sweat_drops": "\ud83d\udca6", "tongue": "\ud83d\udc45", "mag_right": "\ud83d\udd0e", "t_rex": "\ud83e\udd96", "post_office": "\ud83c\udfe3", "shell": "\ud83d\udc1a", "disappointed_relieved": "\ud83d\ude25", "card_index": "\ud83d\udcc7", "oncoming_automobile": "\ud83d\ude98", "passport_control": "\ud83d\udec2", "cherry_blossom": "\ud83c\udf38", "shallow_pan_of_food": "\ud83e\udd58", "heartbeat": "\ud83d\udc93", "crazy_face": "\ud83e\udd2a", "grapes": "\ud83c\udf47", "symbols": "\ud83d\udd23", "gift": "\ud83c\udf81", "scorpion": "\ud83e\udd82", "wedding": "\ud83d\udc92", "last_quarter_moon_with_face": "\ud83c\udf1c", "love_letter": "\ud83d\udc8c", "postal_horn": "\ud83d\udcef", "stuffed_flatbread": "\ud83e\udd59", "heavy_dollar_sign": "\ud83d\udcb2", "love_hotel": "\ud83c\udfe9", "yen": "\ud83d\udcb4", "person_in_steamy_room": "\ud83e\uddd6", "palm_tree": "\ud83c\udf34", "name_badge": "\ud83d\udcdb", "clock430": "\ud83d\udd5f", "bike": "\ud83d\udeb2", "snail": "\ud83d\udc0c", "bowling": "\ud83c\udfb3", "umbrella": "\u2614", "sleeping_accommodation": "\ud83d\udecc", "fireworks": "\ud83c\udf86", "closed_book": "\ud83d\udcd5", "city_sunset": "\ud83c\udf07", "persevere": "\ud83d\ude23", "bento": "\ud83c\udf71", "nut_and_bolt": "\ud83d\udd29", "page_facing_up": "\ud83d\udcc4", "snowman": "\u26c4", "two_women_holding_hands": "\ud83d\udc6d", "regional_indicator_o": "\ud83c\uddf4", "calling": "\ud83d\udcf2", "person_shrugging": "\ud83e\udd37", "sneezing_face": "\ud83e\udd27", "arrows_clockwise": "\ud83d\udd03", "no_pedestrians": "\ud83d\udeb7", "potato": "\ud83e\udd54", "cheese": "\ud83e\uddc0", "full_moon": "\ud83c\udf15", "mount_fuji": "\ud83d\uddfb", "sob": "\ud83d\ude2d", "construction": "\ud83d\udea7", "head_bandage": "\ud83e\udd15", "sailboat": "\u26f5", "slight_frown": "\ud83d\ude41", "ping_pong": "\ud83c\udfd3", "hatched_chick": "\ud83d\udc25", "sun_with_face": "\ud83c\udf1e", "seedling": "\ud83c\udf31", "repeat_one": "\ud83d\udd02", "muscle": "\ud83d\udcaa", "bridge_at_night": "\ud83c\udf09", "raised_hands": "\ud83d\ude4c", "house": "\ud83c\udfe0", "nerd": "\ud83e\udd13", "penguin": "\ud83d\udc27", "peach": "\ud83c\udf51", "dumpling": "\ud83e\udd5f", "watch": "\u231a", "womens": "\ud83d\udeba", "round_pushpin": "\ud83d\udccd", "alarm_clock": "\u23f0", "relieved": "\ud83d\ude0c", "sagittarius": "\u2650", "busstop": "\ud83d\ude8f", "regional_indicator_a": "\ud83c\udde6", "sandal": "\ud83d\udc61", "whale2": "\ud83d\udc0b", "book": "\ud83d\udcd6", "sweat": "\ud83d\ude13", "movie_camera": "\ud83c\udfa5", "clock230": "\ud83d\udd5d", "tiger": "\ud83d\udc2f", "tractor": "\ud83d\ude9c", "smile": "\ud83d\ude04", "vertical_traffic_light": "\ud83d\udea6", "exploding_head": "\ud83e\udd2f", "raised_hand": "\u270b", "smoking": "\ud83d\udeac", "page_with_curl": "\ud83d\udcc3", "exclamation": "\u2757", "fish": "\ud83d\udc1f", "mans_shoe": "\ud83d\udc5e", "sos": "\ud83c\udd98", "unlock": "\ud83d\udd13", "dolls": "\ud83c\udf8e", "ear_of_rice": "\ud83c\udf3e", "cat2": "\ud83d\udc08", "u7121": "\ud83c\ude1a", "repeat": "\ud83d\udd01", "cool": "\ud83c\udd92", "minibus": "\ud83d\ude90", "aerial_tramway": "\ud83d\udea1", "key": "\ud83d\udd11", "child": "\ud83e\uddd2", "camera": "\ud83d\udcf7", "sunflower": "\ud83c\udf3b", "white_check_mark": "\u2705", "white_square_button": "\ud83d\udd33", "banana": "\ud83c\udf4c", "milky_way": "\ud83c\udf0c", "person_gesturing_no": "\ud83d\ude45", "sushi": "\ud83c\udf63", "heart_eyes_cat": "\ud83d\ude3b", "guitar": "\ud83c\udfb8", "pie": "\ud83e\udd67", "calendar": "\ud83d\udcc6", "bear": "\ud83d\udc3b", "person_in_lotus_position": "\ud83e\uddd8", "clock10": "\ud83d\udd59", "top": "\ud83d\udd1d", "fuelpump": "\u26fd", "rainbow": "\ud83c\udf08", "snowboarder": "\ud83c\udfc2", "drum": "\ud83e\udd41", "leaves": "\ud83c\udf43", "first_quarter_moon": "\ud83c\udf13", "spoon": "\ud83e\udd44", "pouting_cat": "\ud83d\ude3e", "shaved_ice": "\ud83c\udf67", "unamused": "\ud83d\ude12", "train2": "\ud83d\ude86", "clock1230": "\ud83d\udd67", "regional_indicator_r": "\ud83c\uddf7", "fast_forward": "\u23e9", "accept": "\ud83c\ude51", "hammer": "\ud83d\udd28", "panda_face": "\ud83d\udc3c", "briefcase": "\ud83d\udcbc", "package": "\ud83d\udce6", "flag_black": "\ud83c\udff4", "smiling_imp": "\ud83d\ude08", "sunrise_over_mountains": "\ud83c\udf04", "airplane_departure": "\ud83d\udeeb", "tiger2": "\ud83d\udc05", "non-potable_water": "\ud83d\udeb1", "bird": "\ud83d\udc26", "barber": "\ud83d\udc88", "cry": "\ud83d\ude22", "billed_cap": "\ud83e\udde2", "pouch": "\ud83d\udc5d", "link": "\ud83d\udd17", "zebra": "\ud83e\udd93", "kiss": "\ud83d\udc8b", "scorpius": "\u264f", "prayer_beads": "\ud83d\udcff", "high_brightness": "\ud83d\udd06", "kissing_smiling_eyes": "\ud83d\ude19", "rhino": "\ud83e\udd8f", "left_luggage": "\ud83d\udec5", "o": "\u2b55", "crying_cat_face": "\ud83d\ude3f", "clock8": "\ud83d\udd57", "dress": "\ud83d\udc57", "clock7": "\ud83d\udd56", "bowl_with_spoon": "\ud83e\udd63", "rolling_eyes": "\ud83d\ude44", "fax": "\ud83d\udce0", "worried": "\ud83d\ude1f", "grey_question": "\u2754", "saxophone": "\ud83c\udfb7", "burrito": "\ud83c\udf2f", "salad": "\ud83e\udd57", "regional_indicator_z": "\ud83c\uddff", "bikini": "\ud83d\udc59", "milk": "\ud83e\udd5b", "stars": "\ud83c\udf20", "lips": "\ud83d\udc44", "cd": "\ud83d\udcbf", "weary": "\ud83d\ude29", "face_with_raised_eyebrow": "\ud83e\udd28", "lizard": "\ud83e\udd8e", "tone1": "\ud83c\udffb", "bullettrain_side": "\ud83d\ude84", "nose": "\ud83d\udc43", "innocent": "\ud83d\ude07", "wilted_rose": "\ud83e\udd40", "mahjong": "\ud83c\udc04", "factory": "\ud83c\udfed", "people_wrestling": "\ud83e\udd3c", "mailbox": "\ud83d\udceb", "rage": "\ud83d\ude21", "wheelchair": "\u267f", "x": "\u274c", "flower_playing_cards": "\ud83c\udfb4", "nauseated_face": "\ud83e\udd22", "underage": "\ud83d\udd1e", "ideograph_advantage": "\ud83c\ude50", "high_heel": "\ud83d\udc60", "dizzy_face": "\ud83d\ude35", "stuck_out_tongue": "\ud83d\ude1b", "mailbox_with_no_mail": "\ud83d\udced", "orange_heart": "\ud83e\udde1", "raised_back_of_hand": "\ud83e\udd1a", "footprints": "\ud83d\udc63", "notebook_with_decorative_cover": "\ud83d\udcd4", "mask": "\ud83d\ude37", "sunglasses": "\ud83d\ude0e", "pancakes": "\ud83e\udd5e", "regional_indicator_f": "\ud83c\uddeb", "dog": "\ud83d\udc36", "pig2": "\ud83d\udc16", "ng": "\ud83c\udd96", "unicorn": "\ud83e\udd84", "triumph": "\ud83d\ude24", "eggplant": "\ud83c\udf46", "egg": "\ud83e\udd5a", "office": "\ud83c\udfe2", "goat": "\ud83d\udc10", "handshake": "\ud83e\udd1d", "star": "\u2b50", "rugby_football": "\ud83c\udfc9", "call_me": "\ud83e\udd19", "rice_cracker": "\ud83c\udf58", "droplet": "\ud83d\udca7", "badminton": "\ud83c\udff8", "waxing_crescent_moon": "\ud83c\udf12", "ocean": "\ud83c\udf0a", "slot_machine": "\ud83c\udfb0", "wine_glass": "\ud83c\udf77", "elephant": "\ud83d\udc18", "blowfish": "\ud83d\udc21", "ledger": "\ud83d\udcd2", "money_mouth": "\ud83e\udd11", "heart_decoration": "\ud83d\udc9f", "arrow_down_small": "\ud83d\udd3d", "station": "\ud83d\ude89", "man_with_chinese_cap": "\ud83d\udc72", "vampire": "\ud83e\udddb", "pencil": "\ud83d\udcdd", "cyclone": "\ud83c\udf00", "mushroom": "\ud83c\udf44", "sandwich": "\ud83e\udd6a", "champagne": "\ud83c\udf7e", "expressionless": "\ud83d\ude11", "cold_sweat": "\ud83d\ude30", "maple_leaf": "\ud83c\udf41", "dromedary_camel": "\ud83d\udc2a", "vs": "\ud83c\udd9a", "person_fencing": "\ud83e\udd3a", "straight_ruler": "\ud83d\udccf", "baby_bottle": "\ud83c\udf7c", "currency_exchange": "\ud83d\udcb1", "regional_indicator_h": "\ud83c\udded", "stuck_out_tongue_closed_eyes": "\ud83d\ude1d", "closed_lock_with_key": "\ud83d\udd10", "eyes": "\ud83d\udc40", "water_buffalo": "\ud83d\udc03", "lock_with_ink_pen": "\ud83d\udd0f", "heavy_plus_sign": "\u2795", "bookmark": "\ud83d\udd16", "soon": "\ud83d\udd1c", "orange_book": "\ud83d\udcd9", "pineapple": "\ud83c\udf4d", "clock9": "\ud83d\udd58", "small_blue_diamond": "\ud83d\udd39", "black_large_square": "\u2b1b", "person_surfing": "\ud83c\udfc4", "leo": "\u264c", "merperson": "\ud83e\udddc", "canoe": "\ud83d\udef6", "rooster": "\ud83d\udc13", "hear_no_evil": "\ud83d\ude49", "corn": "\ud83c\udf3d", "takeout_box": "\ud83e\udd61", "oncoming_taxi": "\ud83d\ude96", "taxi": "\ud83d\ude95", "chart": "\ud83d\udcb9", "goal": "\ud83e\udd45", "melon": "\ud83c\udf48", "notes": "\ud83c\udfb6", "sparkler": "\ud83c\udf87", "dolphin": "\ud83d\udc2c", "speedboat": "\ud83d\udea4", "cancer": "\u264b", "sled": "\ud83d\udef7", "tanabata_tree": "\ud83c\udf8b", "train": "\ud83d\ude8b", "christmas_tree": "\ud83c\udf84", "two_men_holding_hands": "\ud83d\udc6c", "back": "\ud83d\udd19", "balloon": "\ud83c\udf88", "checkered_flag": "\ud83c\udfc1", "loop": "\u27bf", "wc": "\ud83d\udebe", "jeans": "\ud83d\udc56", "green_apple": "\ud83c\udf4f", "crown": "\ud83d\udc51", "cowboy": "\ud83e\udd20", "postbox": "\ud83d\udcee", "volleyball": "\ud83c\udfd0", "upside_down": "\ud83d\ude43", "cricket": "\ud83e\udd97", "custard": "\ud83c\udf6e", "rose": "\ud83c\udf39", "eyeglasses": "\ud83d\udc53", "oncoming_police_car": "\ud83d\ude94", "atm": "\ud83c\udfe7", "flying_saucer": "\ud83d\udef8", "alien": "\ud83d\udc7d", "hamster": "\ud83d\udc39", "trident": "\ud83d\udd31", "disappointed": "\ud83d\ude1e", "cow": "\ud83d\udc2e", "police_officer": "\ud83d\udc6e", "popcorn": "\ud83c\udf7f", "baby_chick": "\ud83d\udc24", "video_camera": "\ud83d\udcf9", "zzz": "\ud83d\udca4", "person_climbing": "\ud83e\uddd7", "star2": "\ud83c\udf1f", "ok": "\ud83c\udd97", "capricorn": "\u2651", "chicken": "\ud83d\udc14", "arrow_double_up": "\u23eb", "zombie": "\ud83e\udddf", "closed_umbrella": "\ud83c\udf02", "person_walking": "\ud83d\udeb6", "lemon": "\ud83c\udf4b", "heartpulse": "\ud83d\udc97", "regional_indicator_i": "\ud83c\uddee", "sauropod": "\ud83e\udd95", "u7981": "\ud83c\ude32", "regional_indicator_w": "\ud83c\uddfc", "evergreen_tree": "\ud83c\udf32", "mobile_phone_off": "\ud83d\udcf4", "koko": "\ud83c\ude01", "poop": "\ud83d\udca9", "cup_with_straw": "\ud83e\udd64", "leopard": "\ud83d\udc06", "radio_button": "\ud83d\udd18", "mega": "\ud83d\udce3", "metal": "\ud83e\udd18", "shushing_face": "\ud83e\udd2b", "stuck_out_tongue_winking_eye": "\ud83d\ude1c", "octopus": "\ud83d\udc19", "boxing_glove": "\ud83e\udd4a", "person_juggling": "\ud83e\udd39", "money_with_wings": "\ud83d\udcb8", "dollar": "\ud83d\udcb5", "bride_with_veil": "\ud83d\udc70", "second_place": "\ud83e\udd48", "spaghetti": "\ud83c\udf5d", "waning_crescent_moon": "\ud83c\udf18", "football": "\ud83c\udfc8", "white_circle": "\u26aa", "full_moon_with_face": "\ud83c\udf1d", "selfie": "\ud83e\udd33", "tone3": "\ud83c\udffd", "rabbit": "\ud83d\udc30", "computer": "\ud83d\udcbb", "clock11": "\ud83d\udd5a", "heavy_minus_sign": "\u2796", "synagogue": "\ud83d\udd4d", "hourglass": "\u231b", "gem": "\ud83d\udc8e", "person_doing_cartwheel": "\ud83e\udd38", "new_moon_with_face": "\ud83c\udf1a", "sunrise": "\ud83c\udf05", "regional_indicator_x": "\ud83c\uddfd", "open_file_folder": "\ud83d\udcc2", "gift_heart": "\ud83d\udc9d", "tada": "\ud83c\udf89", "green_heart": "\ud83d\udc9a", "battery": "\ud83d\udd0b", "regional_indicator_t": "\ud83c\uddf9", "wrench": "\ud83d\udd27", "aries": "\u2648", "man_in_tuxedo": "\ud83e\udd35", "regional_indicator_e": "\ud83c\uddea", "regional_indicator_l": "\ud83c\uddf1", "cake": "\ud83c\udf70", "clapper": "\ud83c\udfac", "japanese_castle": "\ud83c\udfef", "crystal_ball": "\ud83d\udd2e", "golf": "\u26f3", "no_mobile_phones": "\ud83d\udcf5", "person_biking": "\ud83d\udeb4", "icecream": "\ud83c\udf66", "mage": "\ud83e\uddd9", "bookmark_tabs": "\ud83d\udcd1", "tone4": "\ud83c\udffe", "mountain_cableway": "\ud83d\udea0", "person_playing_handball": "\ud83e\udd3e", "bulb": "\ud83d\udca1", "clock330": "\ud83d\udd5e", "metro": "\ud83d\ude87", "wave": "\ud83d\udc4b", "whale": "\ud83d\udc33", "strawberry": "\ud83c\udf53", "hatching_chick": "\ud83d\udc23", "trolleybus": "\ud83d\ude8e", "lollipop": "\ud83c\udf6d", "clipboard": "\ud83d\udccb", "point_right": "\ud83d\udc49", "u6307": "\ud83c\ude2f", "santa": "\ud83c\udf85", "hibiscus": "\ud83c\udf3a", "green_book": "\ud83d\udcd7", "skull": "\ud83d\udc80", "tumbler_glass": "\ud83e\udd43", "clock2": "\ud83d\udd51", "open_mouth": "\ud83d\ude2e", "bouquet": "\ud83d\udc90", "champagne_glass": "\ud83e\udd42", "poodle": "\ud83d\udc29", "hushed": "\ud83d\ude2f", "earth_asia": "\ud83c\udf0f", "face_with_monocle": "\ud83e\uddd0", "libra": "\u264e", "clock5": "\ud83d\udd54", "ambulance": "\ud83d\ude91", "u5272": "\ud83c\ude39", "lipstick": "\ud83d\udc84", "apple": "\ud83c\udf4e", "headphones": "\ud83c\udfa7", "turkey": "\ud83e\udd83", "pretzel": "\ud83e\udd68", "bug": "\ud83d\udc1b", "school": "\ud83c\udfeb", "speaker": "\ud83d\udd08", "boot": "\ud83d\udc62", "cat": "\ud83d\udc31", "dancer": "\ud83d\udc83", "no_entry": "\u26d4", "kissing_cat": "\ud83d\ude3d", "art": "\ud83c\udfa8", "coat": "\ud83e\udde5", "credit_card": "\ud83d\udcb3", "customs": "\ud83d\udec3", "broccoli": "\ud83e\udd66", "point_left": "\ud83d\udc48", "canned_food": "\ud83e\udd6b", "sheep": "\ud83d\udc11", "person_bowing": "\ud83d\ude47", "scroll": "\ud83d\udcdc", "martial_arts_uniform": "\ud83e\udd4b", "amphora": "\ud83c\udffa", "thought_balloon": "\ud83d\udcad", "no_bell": "\ud83d\udd15", "musical_keyboard": "\ud83c\udfb9", "people_with_bunny_ears_partying": "\ud83d\udc6f", "european_castle": "\ud83c\udff0", "punch": "\ud83d\udc4a", "camera_with_flash": "\ud83d\udcf8", "regional_indicator_p": "\ud83c\uddf5", "red_car": "\ud83d\ude97", "regional_indicator_j": "\ud83c\uddef", "owl": "\ud83e\udd89", "chart_with_downwards_trend": "\ud83d\udcc9", "older_woman": "\ud83d\udc75", "gemini": "\u264a", "incoming_envelope": "\ud83d\udce8", "waxing_gibbous_moon": "\ud83c\udf14", "toilet": "\ud83d\udebd", "dragon_face": "\ud83d\udc32", "koala": "\ud83d\udc28", "tone5": "\ud83c\udfff", "kiwi": "\ud83e\udd5d", "dash": "\ud83d\udca8", "imp": "\ud83d\udc7f", "tent": "\u26fa", "regional_indicator_b": "\ud83c\udde7", "monorail": "\ud83d\ude9d", "ox": "\ud83d\udc02", "giraffe": "\ud83e\udd92", "new": "\ud83c\udd95", "person_raising_hand": "\ud83d\ude4b", "japan": "\ud83d\uddfe", "rice": "\ud83c\udf5a", "ticket": "\ud83c\udfab", "rotating_light": "\ud83d\udea8", "loudspeaker": "\ud83d\udce2", "person_getting_massage": "\ud83d\udc86", "loud_sound": "\ud83d\udd0a", "hugging": "\ud83e\udd17", "herb": "\ud83c\udf3f", "baby": "\ud83d\udc76", "angel": "\ud83d\udc7c", "athletic_shoe": "\ud83d\udc5f", "euro": "\ud83d\udcb6", "ram": "\ud83d\udc0f", "large_orange_diamond": "\ud83d\udd36", "red_circle": "\ud83d\udd34", "ferris_wheel": "\ud83c\udfa1", "drooling_face": "\ud83e\udd24", "microscope": "\ud83d\udd2c", "middle_finger": "\ud83d\udd95", "pager": "\ud83d\udcdf", "pensive": "\ud83d\ude14", "potable_water": "\ud83d\udeb0", "abc": "\ud83d\udd24", "four_leaf_clover": "\ud83c\udf40", "vulcan": "\ud83d\udd96", "french_bread": "\ud83e\udd56", "motor_scooter": "\ud83d\udef5", "moneybag": "\ud83d\udcb0", "sparkles": "\u2728", "gloves": "\ud83e\udde4", "envelope_with_arrow": "\ud83d\udce9", "thumbsdown": "\ud83d\udc4e", "regional_indicator_g": "\ud83c\uddec", "video_game": "\ud83c\udfae", "on": "\ud83d\udd1b", "open_hands": "\ud83d\udc50", "monkey_face": "\ud83d\udc35", "mountain_railway": "\ud83d\ude9e", "bee": "\ud83d\udc1d", "scooter": "\ud83d\udef4", "fishing_pole_and_fish": "\ud83c\udfa3", "smiley_cat": "\ud83d\ude3a", "heart_eyes": "\ud83d\ude0d", "horse_racing": "\ud83c\udfc7", "ear": "\ud83d\udc42", "blue_circle": "\ud83d\udd35", "crossed_flags": "\ud83c\udf8c", "black_joker": "\ud83c\udccf", "six_pointed_star": "\ud83d\udd2f", "fountain": "\u26f2", "free": "\ud83c\udd93", "tennis": "\ud83c\udfbe", "yum": "\ud83d\ude0b", "fried_shrimp": "\ud83c\udf64", "dragon": "\ud83d\udc09", "purse": "\ud83d\udc5b", "clock1": "\ud83d\udd50", "airplane_arriving": "\ud83d\udeec", "cucumber": "\ud83e\udd52", "man_dancing": "\ud83d\udd7a", "clock730": "\ud83d\udd62", "deer": "\ud83e\udd8c", "meat_on_bone": "\ud83c\udf56", "bomb": "\ud83d\udca3", "night_with_stars": "\ud83c\udf03", "snake": "\ud83d\udc0d", "ramen": "\ud83c\udf5c", "end": "\ud83d\udd1a", "do_not_litter": "\ud83d\udeaf", "joy": "\ud83d\ude02", "light_rail": "\ud83d\ude88", "game_die": "\ud83c\udfb2", "violin": "\ud83c\udfbb", "tone2": "\ud83c\udffc", "tropical_drink": "\ud83c\udf79", "love_you_gesture": "\ud83e\udd1f", "cherries": "\ud83c\udf52", "traffic_light": "\ud83d\udea5", "iphone": "\ud83d\udcf1", "socks": "\ud83e\udde6", "wind_chime": "\ud83c\udf90", "no_entry_sign": "\ud83d\udeab", "elf": "\ud83e\udddd", "squid": "\ud83e\udd91", "person_pouting": "\ud83d\ude4e", "smile_cat": "\ud83d\ude38", "beers": "\ud83c\udf7b", "minidisc": "\ud83d\udcbd", "clock4": "\ud83d\udd53", "ice_cream": "\ud83c\udf68", "cocktail": "\ud83c\udf78", "clock3": "\ud83d\udd52", "frowning": "\ud83d\ude26", "hamburger": "\ud83c\udf54", "brain": "\ud83e\udde0", "heavy_division_sign": "\u2797", "tophat": "\ud83c\udfa9", "no_mouth": "\ud83d\ude36", "ski": "\ud83c\udfbf", "right_facing_fist": "\ud83e\udd1c", "mailbox_closed": "\ud83d\udcea", "chocolate_bar": "\ud83c\udf6b", "rabbit2": "\ud83d\udc07", "honey_pot": "\ud83c\udf6f", "izakaya_lantern": "\ud83c\udfee", "articulated_lorry": "\ud83d\ude9b", "face_with_hand_over_mouth": "\ud83e\udd2d", "japanese_ogre": "\ud83d\udc79", "zap": "\u26a1", "rocket": "\ud83d\ude80", "pizza": "\ud83c\udf55", "pound": "\ud83d\udcb7", "person_swimming": "\ud83c\udfca", "anchor": "\u2693", "coconut": "\ud83e\udd65", "sparkling_heart": "\ud83d\udc96", "older_man": "\ud83d\udc74", "mouse2": "\ud83d\udc01", "angry": "\ud83d\ude20", "up": "\ud83c\udd99", "gorilla": "\ud83e\udd8d", "children_crossing": "\ud83d\udeb8", "smirk_cat": "\ud83d\ude3c", "pregnant_woman": "\ud83e\udd30", "electric_plug": "\ud83d\udd0c", "dog2": "\ud83d\udc15", "question": "\u2753", "carousel_horse": "\ud83c\udfa0", "church": "\u26ea", "outbox_tray": "\ud83d\udce4", "cinema": "\ud83c\udfa6", "flushed": "\ud83d\ude33", "blush": "\ud83d\ude0a", "medal": "\ud83c\udfc5", "coffee": "\u2615", "gun": "\ud83d\udd2b", "city_dusk": "\ud83c\udf06", "watermelon": "\ud83c\udf49", "cricket_game": "\ud83c\udfcf", "shower": "\ud83d\udebf", "mute": "\ud83d\udd07", "breast_feeding": "\ud83e\udd31", "sweat_smile": "\ud83d\ude05", "construction_worker": "\ud83d\udc77", "cow2": "\ud83d\udc04", "arrows_counterclockwise": "\ud83d\udd04", "u6e80": "\ud83c\ude35", "grinning": "\ud83d\ude00", "globe_with_meridians": "\ud83c\udf10", "diamond_shape_with_a_dot_inside": "\ud83d\udca0", "deciduous_tree": "\ud83c\udf33", "shark": "\ud83e\udd88", "tram": "\ud83d\ude8a", "person_rowing_boat": "\ud83d\udea3", "chopsticks": "\ud83e\udd62", "black_heart": "\ud83d\udda4", "seat": "\ud83d\udcba", "kissing": "\ud83d\ude17", "laughing": "\ud83d\ude06", "slight_smile": "\ud83d\ude42", "radio": "\ud83d\udcfb", "arrow_up_small": "\ud83d\udd3c", "dango": "\ud83c\udf61", "rofl": "\ud83e\udd23", "see_no_evil": "\ud83d\ude48", "thermometer_face": "\ud83e\udd12", "hotdog": "\ud83c\udf2d", "virgo": "\u264d", "poultry_leg": "\ud83c\udf57", "hotel": "\ud83c\udfe8", "wolf": "\ud83d\udc3a", "curry": "\ud83c\udf5b", "regional_indicator_v": "\ud83c\uddfb", "crab": "\ud83e\udd80", "tired_face": "\ud83d\ude2b", "place_of_worship": "\ud83d\uded0", "ok_hand": "\ud83d\udc4c", "speech_balloon": "\ud83d\udcac", "sleepy": "\ud83d\ude2a", "earth_africa": "\ud83c\udf0d", "police_car": "\ud83d\ude93", "small_red_triangle_down": "\ud83d\udd3b", "bearded_person": "\ud83e\uddd4", "curling_stone": "\ud83e\udd4c", "scarf": "\ud83e\udde3", "fire": "\ud83d\udd25", "file_folder": "\ud83d\udcc1", "zipper_mouth": "\ud83e\udd10", "new_moon": "\ud83c\udf11", "regional_indicator_n": "\ud83c\uddf3", "negative_squared_cross_mark": "\u274e", "newspaper": "\ud83d\udcf0", "dvd": "\ud83d\udcc0", "pear": "\ud83c\udf50", "partly_sunny": "\u26c5", "black_square_button": "\ud83d\udd32", "low_brightness": "\ud83d\udd05", "sake": "\ud83c\udf76", "bow_and_arrow": "\ud83c\udff9", "cooking": "\ud83c\udf73", "fish_cake": "\ud83c\udf65", "tomato": "\ud83c\udf45", "couple_with_heart": "\ud83d\udc91", "telephone_receiver": "\ud83d\udcde", "triangular_flag_on_post": "\ud83d\udea9", "jack_o_lantern": "\ud83c\udf83", "blue_book": "\ud83d\udcd8", "clock530": "\ud83d\udd60", "u6709": "\ud83c\ude36", "palms_up_together": "\ud83e\udd32", "lion_face": "\ud83e\udd81", "lock": "\ud83d\udd12", "duck": "\ud83e\udd86", "truck": "\ud83d\ude9a", "oden": "\ud83c\udf62", "busts_in_silhouette": "\ud83d\udc65", "hourglass_flowing_sand": "\u23f3", "frog": "\ud83d\udc38", "fox": "\ud83e\udd8a", "bread": "\ud83c\udf5e", "put_litter_in_its_place": "\ud83d\udeae", "couple": "\ud83d\udc6b", "bamboo": "\ud83c\udf8d", "regional_indicator_c": "\ud83c\udde8", "menorah": "\ud83d\udd4e", "circus_tent": "\ud83c\udfaa", "lying_face": "\ud83e\udd25", "small_orange_diamond": "\ud83d\udd38", "ship": "\ud83d\udea2", "person_frowning": "\ud83d\ude4d", "racehorse": "\ud83d\udc0e", "thumbsup": "\ud83d\udc4d", "cupid": "\ud83d\udc98", "robot": "\ud83e\udd16", "fallen_leaf": "\ud83c\udf42", "pig_nose": "\ud83d\udc3d", "vibration_mode": "\ud83d\udcf3", "necktie": "\ud83d\udc54", "boy": "\ud83d\udc66", "house_with_garden": "\ud83c\udfe1", "point_down": "\ud83d\udc47", "grey_exclamation": "\u2755", "books": "\ud83d\udcda", "regional_indicator_k": "\ud83c\uddf0", "shirt": "\ud83d\udc55", "fries": "\ud83c\udf5f", "dart": "\ud83c\udfaf", "tea": "\ud83c\udf75", "mrs_claus": "\ud83e\udd36", "suspension_railway": "\ud83d\ude9f", "baby_symbol": "\ud83d\udebc", "sweet_potato": "\ud83c\udf60", "butterfly": "\ud83e\udd8b", "performing_arts": "\ud83c\udfad", "notebook": "\ud83d\udcd3", "bat": "\ud83e\udd87"}
\ No newline at end of file
diff --git a/priv/static/static/js/app.30c01d7540d43b760f03.js b/priv/static/static/js/app.30c01d7540d43b760f03.js
new file mode 100644
index 000000000..60e8ac118
Binary files /dev/null and b/priv/static/static/js/app.30c01d7540d43b760f03.js differ
diff --git a/priv/static/static/js/app.30c01d7540d43b760f03.js.map b/priv/static/static/js/app.30c01d7540d43b760f03.js.map
new file mode 100644
index 000000000..5064f6398
Binary files /dev/null and b/priv/static/static/js/app.30c01d7540d43b760f03.js.map differ
diff --git a/priv/static/static/js/app.fefccf252cac9e1310ea.js b/priv/static/static/js/app.fefccf252cac9e1310ea.js
deleted file mode 100644
index 343f7503d..000000000
Binary files a/priv/static/static/js/app.fefccf252cac9e1310ea.js and /dev/null differ
diff --git a/priv/static/static/js/app.fefccf252cac9e1310ea.js.map b/priv/static/static/js/app.fefccf252cac9e1310ea.js.map
deleted file mode 100644
index b51ed9f3a..000000000
Binary files a/priv/static/static/js/app.fefccf252cac9e1310ea.js.map and /dev/null differ
diff --git a/priv/static/static/js/manifest.15dfe939c498cca9840c.js b/priv/static/static/js/manifest.15dfe939c498cca9840c.js
new file mode 100644
index 000000000..9cd39983a
Binary files /dev/null and b/priv/static/static/js/manifest.15dfe939c498cca9840c.js differ
diff --git a/priv/static/static/js/manifest.15dfe939c498cca9840c.js.map b/priv/static/static/js/manifest.15dfe939c498cca9840c.js.map
new file mode 100644
index 000000000..116fca551
Binary files /dev/null and b/priv/static/static/js/manifest.15dfe939c498cca9840c.js.map differ
diff --git a/priv/static/static/js/manifest.ee87253244897e08bdce.js b/priv/static/static/js/manifest.ee87253244897e08bdce.js
deleted file mode 100644
index cf9d9c73d..000000000
Binary files a/priv/static/static/js/manifest.ee87253244897e08bdce.js and /dev/null differ
diff --git a/priv/static/static/js/manifest.ee87253244897e08bdce.js.map b/priv/static/static/js/manifest.ee87253244897e08bdce.js.map
deleted file mode 100644
index 97fcf42cf..000000000
Binary files a/priv/static/static/js/manifest.ee87253244897e08bdce.js.map and /dev/null differ
diff --git a/priv/static/static/js/vendor.409059e5a814f448f5bc.js b/priv/static/static/js/vendor.409059e5a814f448f5bc.js
new file mode 100644
index 000000000..1dae3910d
Binary files /dev/null and b/priv/static/static/js/vendor.409059e5a814f448f5bc.js differ
diff --git a/priv/static/static/js/vendor.409059e5a814f448f5bc.js.map b/priv/static/static/js/vendor.409059e5a814f448f5bc.js.map
new file mode 100644
index 000000000..0fc735df4
Binary files /dev/null and b/priv/static/static/js/vendor.409059e5a814f448f5bc.js.map differ
diff --git a/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js b/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js
deleted file mode 100644
index 47efc7091..000000000
Binary files a/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js and /dev/null differ
diff --git a/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js.map b/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js.map
deleted file mode 100644
index d23d16168..000000000
Binary files a/priv/static/static/js/vendor.50cd70f77f559bfe1f27.js.map and /dev/null differ
diff --git a/test/notification_test.exs b/test/notification_test.exs
index eee1c9fa3..0a4462241 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -14,9 +14,9 @@ test "notifies someone when they are directly addressed" do
{:ok, [notification, other_notification]} = Notification.create_notifications(activity)
- assert notification.user_id == other_user.id
+ notified_ids = Enum.sort([notification.user_id, other_notification.user_id])
+ assert notified_ids == [other_user.id, third_user.id]
assert notification.activity_id == activity.id
- assert other_notification.user_id == third_user.id
assert other_notification.activity_id == activity.id
end
end
diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs
index eccfe0b36..5eefa61e1 100644
--- a/test/web/mastodon_api/account_view_test.exs
+++ b/test/web/mastodon_api/account_view_test.exs
@@ -19,10 +19,10 @@ test "Represent a user account" do
statuses_count: 5,
note: user.bio,
url: user.ap_id,
- avatar: "https://placehold.it/48x48",
- avatar_static: "https://placehold.it/48x48",
- header: "https://placehold.it/700x335",
- header_static: "https://placehold.it/700x335",
+ avatar: "http://localhost:4001/images/avi.png",
+ avatar_static: "http://localhost:4001/images/avi.png",
+ header: "http://localhost:4001/images/banner.png",
+ header_static: "http://localhost:4001/images/banner.png",
source: %{
note: "",
privacy: "public",
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index fc0010569..93b29dfae 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -35,7 +35,7 @@ test "the public timeline", %{conn: conn} do
{:ok, [_activity]} = OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
conn = conn
- |> get("/api/v1/timelines/public")
+ |> get("/api/v1/timelines/public", %{"local" => "False"})
assert length(json_response(conn, 200)) == 2
@@ -43,6 +43,11 @@ test "the public timeline", %{conn: conn} do
|> get("/api/v1/timelines/public", %{"local" => "True"})
assert [%{"content" => "test"}] = json_response(conn, 200)
+
+ conn = build_conn()
+ |> get("/api/v1/timelines/public", %{"local" => "1"})
+
+ assert [%{"content" => "test"}] = json_response(conn, 200)
end
test "posting a status", %{conn: conn} do
@@ -50,9 +55,9 @@ test "posting a status", %{conn: conn} do
conn = conn
|> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "cofe", "spoiler_text" => "2hu"})
+ |> post("/api/v1/statuses", %{"status" => "cofe", "spoiler_text" => "2hu", "sensitive" => "false"})
- assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu"} = json_response(conn, 200)
+ assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = json_response(conn, 200)
assert Repo.get(Activity, id)
end
@@ -145,7 +150,7 @@ test "list of notifications", %{conn: conn} do
|> assign(:user, user)
|> get("/api/v1/notifications")
- expected_response = "hi @#{user.nickname}"
+ expected_response = "hi @#{user.nickname}"
assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
assert response == expected_response
end
@@ -161,7 +166,7 @@ test "getting a single notification", %{conn: conn} do
|> assign(:user, user)
|> get("/api/v1/notifications/#{notification.id}")
- expected_response = "hi @#{user.nickname}"
+ expected_response = "hi @#{user.nickname}"
assert %{"status" => %{"content" => response}} = json_response(conn, 200)
assert response == expected_response
end
@@ -581,11 +586,14 @@ test "get instance information" do
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
+ Pleroma.Stats.update_stats()
+
conn = conn
|> get("/api/v1/instance")
assert result = json_response(conn, 200)
assert result["stats"]["user_count"] == 2
+ assert result["stats"]["status_count"] == 1
end
end
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index 93c0b7236..0d396f3b8 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -56,7 +56,9 @@ test "a note activity" do
test "contains mentions" do
incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
- user = insert(:user, %{ap_id: "https://pleroma.soykaf.com/users/lain"})
+ # a user with this ap id might be in the cache.
+ recipient = "https://pleroma.soykaf.com/users/lain"
+ user = User.get_cached_by_ap_id(recipient) || insert(:user, %{ap_id: recipient})
{:ok, [activity]} = OStatus.handle_incoming(incoming)
diff --git a/test/web/ostatus/feed_representer_test.exs b/test/web/ostatus/feed_representer_test.exs
index df5a964e2..e10936366 100644
--- a/test/web/ostatus/feed_representer_test.exs
+++ b/test/web/ostatus/feed_representer_test.exs
@@ -26,6 +26,7 @@ test "returns a feed of the last 20 items of the user" do
#{OStatus.feed_path(user)}
#{user.nickname}'s timeline
#{most_recent_update}
+ #{User.avatar_url(user)}
diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs
index de01612b3..b27f8cb55 100644
--- a/test/web/ostatus/ostatus_test.exs
+++ b/test/web/ostatus/ostatus_test.exs
@@ -302,7 +302,8 @@ test "it returns user info in a hash" do
"host" => "social.heldscal.la",
"fqn" => user,
"bio" => "cofe",
- "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]}
+ "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]},
+ "subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}"
}
assert data == expected
end
@@ -325,7 +326,8 @@ test "it works with the uri" do
"host" => "social.heldscal.la",
"fqn" => user,
"bio" => "cofe",
- "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]}
+ "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]},
+ "subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}"
}
assert data == expected
end
diff --git a/test/web/ostatus/user_representer_test.exs b/test/web/ostatus/user_representer_test.exs
index d5d70f5c6..b22420379 100644
--- a/test/web/ostatus/user_representer_test.exs
+++ b/test/web/ostatus/user_representer_test.exs
@@ -21,6 +21,7 @@ test "returns a user with id, uri, name and link" do
#{user.bio}
#{user.nickname}
+
"""
assert clean(res) == clean(expected)
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 90d0fa654..39f1cdd4c 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -518,7 +518,7 @@ test "it returns a user's followers", %{conn: conn} do
end
describe "GET /api/statuses/friends" do
- test "it returns a user's friends", %{conn: conn} do
+ test "it returns the logged in user's friends", %{conn: conn} do
user = insert(:user)
followed_one = insert(:user)
followed_two = insert(:user)
@@ -533,6 +533,36 @@ test "it returns a user's friends", %{conn: conn} do
assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
end
+
+ test "it returns a given user's friends with user_id", %{conn: conn} do
+ user = insert(:user)
+ followed_one = insert(:user)
+ followed_two = insert(:user)
+ not_followed = insert(:user)
+
+ {:ok, user} = User.follow(user, followed_one)
+ {:ok, user} = User.follow(user, followed_two)
+
+ conn = conn
+ |> get("/api/statuses/friends", %{"user_id" => user.id})
+
+ assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
+ end
+
+ test "it returns a given user's friends with screen_name", %{conn: conn} do
+ user = insert(:user)
+ followed_one = insert(:user)
+ followed_two = insert(:user)
+ not_followed = insert(:user)
+
+ {:ok, user} = User.follow(user, followed_one)
+ {:ok, user} = User.follow(user, followed_two)
+
+ conn = conn
+ |> get("/api/statuses/friends", %{"screen_name" => user.nickname})
+
+ assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
+ end
end
describe "GET /friends/ids" do
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 96552f97e..ac62880d5 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -34,7 +34,7 @@ test "create a status" do
{ :ok, activity = %Activity{} } = TwitterAPI.create_status(user, input)
- assert get_in(activity.data, ["object", "content"]) == "Hello again, @shp.<script></script>
This is on another :moominmamma: line. #2hu #epic #phantasmagoric
image.jpg"
+ assert get_in(activity.data, ["object", "content"]) == "Hello again, @shp.<script></script>
This is on another :moominmamma: line. #2hu #epic #phantasmagoric
image.jpg"
assert get_in(activity.data, ["object", "type"]) == "Note"
assert get_in(activity.data, ["object", "actor"]) == user.ap_id
assert get_in(activity.data, ["actor"]) == user.ap_id
@@ -291,7 +291,7 @@ test "it adds user links to an existing text" do
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
mentions = Pleroma.Formatter.parse_mentions(text)
- expected_text = "@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme"
+ expected_text = "@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme"
assert Utils.add_user_links(text, mentions) == expected_text
end
@@ -404,7 +404,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_activity_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/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 18a19ef70..d5d2f0adc 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -30,10 +30,11 @@ test "A user" do
User.follow(follower, user)
User.follow(second_follower, user)
User.follow(user, follower)
+ {:ok, user} = User.update_follower_count(user)
+ Cachex.set(:user_cache, "user_info:#{user.id}", User.user_info(Repo.get!(User, user.id)))
- user = Repo.get!(User, user.id)
-
- image = "https://placehold.it/48x48"
+ image = "http://localhost:4001/images/avi.png"
+ banner = "http://localhost:4001/images/banner.png"
represented = %{
"id" => user.id,
@@ -54,8 +55,9 @@ test "A user" do
"statusnet_blocking" => false,
"rights" => %{},
"statusnet_profile_url" => user.ap_id,
- "cover_photo" => nil,
- "background_image" => nil
+ "cover_photo" => banner,
+ "background_image" => nil,
+ "is_local" => true
}
assert represented == UserView.render("show.json", %{user: user})
@@ -64,7 +66,9 @@ test "A user" do
test "A user for a given other follower", %{user: user} do
{:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]})
{:ok, user} = User.update_follower_count(user)
- image = "https://placehold.it/48x48"
+ image = "http://localhost:4001/images/avi.png"
+ banner = "http://localhost:4001/images/banner.png"
+
represented = %{
"id" => user.id,
"name" => user.name,
@@ -84,8 +88,9 @@ test "A user for a given other follower", %{user: user} do
"statusnet_blocking" => false,
"rights" => %{},
"statusnet_profile_url" => user.ap_id,
- "cover_photo" => nil,
- "background_image" => nil
+ "cover_photo" => banner,
+ "background_image" => nil,
+ "is_local" => true
}
assert represented == UserView.render("show.json", %{user: user, for: follower})
@@ -95,7 +100,9 @@ test "A user that follows you", %{user: user} do
follower = insert(:user)
{:ok, follower} = User.follow(follower, user)
{:ok, user} = User.update_follower_count(user)
- image = "https://placehold.it/48x48"
+ image = "http://localhost:4001/images/avi.png"
+ banner = "http://localhost:4001/images/banner.png"
+
represented = %{
"id" => follower.id,
"name" => follower.name,
@@ -115,8 +122,9 @@ test "A user that follows you", %{user: user} do
"statusnet_blocking" => false,
"rights" => %{},
"statusnet_profile_url" => follower.ap_id,
- "cover_photo" => nil,
- "background_image" => nil
+ "cover_photo" => banner,
+ "background_image" => nil,
+ "is_local" => true
}
assert represented == UserView.render("show.json", %{user: follower, for: user})
@@ -126,7 +134,9 @@ test "A blocked user for the blocker", %{user: user} do
user = insert(:user)
blocker = insert(:user)
User.block(blocker, user)
- image = "https://placehold.it/48x48"
+ image = "http://localhost:4001/images/avi.png"
+ banner = "http://localhost:4001/images/banner.png"
+
represented = %{
"id" => user.id,
"name" => user.name,
@@ -146,8 +156,9 @@ test "A blocked user for the blocker", %{user: user} do
"statusnet_blocking" => true,
"rights" => %{},
"statusnet_profile_url" => user.ap_id,
- "cover_photo" => nil,
- "background_image" => nil
+ "cover_photo" => banner,
+ "background_image" => nil,
+ "is_local" => true
}
blocker = Repo.get(User, blocker.id)