From 371a4aed2ca9f6926e49f6791c8b4d14292d20e5 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sat, 13 Apr 2019 17:40:42 +0700 Subject: [PATCH 001/202] Add User.Info.email_notifications --- lib/pleroma/user/info.ex | 27 +++++++++++++++++++ .../20190412052952_add_user_info_fields.exs | 20 ++++++++++++++ test/user_info_test.exs | 24 +++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 priv/repo/migrations/20190412052952_add_user_info_fields.exs create mode 100644 test/user_info_test.exs diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 5afa7988c..194dd5581 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -8,6 +8,8 @@ defmodule Pleroma.User.Info do alias Pleroma.User.Info + @type t :: %__MODULE__{} + embedded_schema do field(:banner, :map, default: %{}) field(:background, :map, default: %{}) @@ -40,6 +42,7 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:email_notifications, :map, default: %{"digest" => true}) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} @@ -75,6 +78,30 @@ def update_notification_settings(info, settings) do |> validate_required([:notification_settings]) end + @doc """ + Update email notifications in the given User.Info struct. + + Examples: + + iex> update_email_notifications(%Pleroma.User.Info{email_notifications: %{"digest" => false}}, %{"digest" => true}) + %Pleroma.User.Info{email_notifications: %{"digest" => true}} + + """ + @spec update_email_notifications(t(), map()) :: Ecto.Changeset.t() + def update_email_notifications(info, settings) do + email_notifications = + info.email_notifications + |> Map.merge(settings) + |> Map.take(["digest"]) + + params = %{email_notifications: email_notifications} + fields = [:email_notifications] + + info + |> cast(params, fields) + |> validate_required(fields) + end + def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/priv/repo/migrations/20190412052952_add_user_info_fields.exs b/priv/repo/migrations/20190412052952_add_user_info_fields.exs new file mode 100644 index 000000000..203d0fc3b --- /dev/null +++ b/priv/repo/migrations/20190412052952_add_user_info_fields.exs @@ -0,0 +1,20 @@ +defmodule Pleroma.Repo.Migrations.AddEmailNotificationsToUserInfo do + use Ecto.Migration + + def up do + execute(" + UPDATE users + SET info = info || '{ + \"email_notifications\": { + \"digest\": true + } + }'") + end + + def down do + execute(" + UPDATE users + SET info = info - 'email_notifications' + ") + end +end diff --git a/test/user_info_test.exs b/test/user_info_test.exs new file mode 100644 index 000000000..2d795594e --- /dev/null +++ b/test/user_info_test.exs @@ -0,0 +1,24 @@ +defmodule Pleroma.UserInfoTest do + alias Pleroma.Repo + alias Pleroma.User.Info + + use Pleroma.DataCase + + import Pleroma.Factory + + describe "update_email_notifications/2" do + setup do + user = insert(:user, %{info: %{email_notifications: %{"digest" => true}}}) + + {:ok, user: user} + end + + test "Notifications are updated", %{user: user} do + true = user.info.email_notifications["digest"] + changeset = Info.update_email_notifications(user.info, %{"digest" => false}) + assert changeset.valid? + {:ok, result} = Ecto.Changeset.apply_action(changeset, :insert) + assert result.email_notifications["digest"] == false + end + end +end From dc21181f6504b55afa68de63f170fcb0f1084a6b Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 14 Apr 2019 22:29:05 +0700 Subject: [PATCH 002/202] Update updated_at field on notification read --- lib/pleroma/notification.ex | 5 ++++- test/notification_test.exs | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b357d5399..29845b9da 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -58,7 +58,10 @@ def set_read_up_to(%{id: user_id} = _user, id) do where: n.user_id == ^user_id, where: n.id <= ^id, update: [ - set: [seen: true] + set: [ + seen: true, + updated_at: ^NaiveDateTime.utc_now() + ] ] ) diff --git a/test/notification_test.exs b/test/notification_test.exs index c3db77b6c..907b9e669 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -300,6 +300,29 @@ test "it sets all notifications as read up to a specified notification ID" do assert n2.seen == true assert n3.seen == false end + + test "Updates `updated_at` field" do + user1 = insert(:user) + user2 = insert(:user) + + Enum.each(0..10, fn i -> + {:ok, _activity} = + TwitterAPI.create_status(user1, %{ + "status" => "#{i} hi @#{user2.nickname}" + }) + end) + + Process.sleep(1000) + + [notification | _] = Notification.for_user(user2) + + Notification.set_read_up_to(user2, notification.id) + + Notification.for_user(user2) + |> Enum.each(fn notification -> + assert notification.updated_at > notification.inserted_at + end) + end end describe "notification target determination" do From 2f0203a4a1c7a507aa5cf50be2fd372536ebfc81 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Wed, 17 Apr 2019 16:59:05 +0700 Subject: [PATCH 003/202] Resolve conflicts --- config/config.exs | 10 ++++++++ lib/pleroma/user.ex | 2 ++ mix.exs | 5 ++-- mix.lock | 51 +++++++++++++++++++++----------------- test/notification_test.exs | 22 ++++++++++------ 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/config/config.exs b/config/config.exs index 595e3505c..747d33884 100644 --- a/config/config.exs +++ b/config/config.exs @@ -464,6 +464,16 @@ total_user_limit: 300, enabled: true +config :pleroma, :email_notifications, + digest: %{ + # When to send digest email, in crontab format (https://en.wikipedia.org/wiki/Cron) + schedule: "0 0 * * 0", + # Minimum interval between digest emails to one user + interval: 7, + # Minimum user inactivity threshold + inactivity_threshold: 7 + } + # 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/lib/pleroma/user.ex b/lib/pleroma/user.ex index 78eb29ddd..0982f6ed8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -55,6 +55,8 @@ defmodule Pleroma.User do field(:tags, {:array, :string}, default: []) field(:bookmarks, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime_usec) + field(:current_sign_in_at, :naive_datetime) + field(:last_digest_emailed_at, :naive_datetime) has_many(:notifications, Notification) has_many(:registrations, Registration) embeds_one(:info, Pleroma.User.Info) diff --git a/mix.exs b/mix.exs index 15e182239..da2e284f8 100644 --- a/mix.exs +++ b/mix.exs @@ -8,7 +8,7 @@ def project do elixir: "~> 1.7", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), - elixirc_options: [warnings_as_errors: true], + # elixirc_options: [warnings_as_errors: true], xref: [exclude: [:eldap]], start_permanent: Mix.env() == :prod, aliases: aliases(), @@ -110,7 +110,8 @@ defp deps do {:prometheus_ecto, "~> 1.4"}, {:prometheus_process_collector, "~> 1.4"}, {:recon, github: "ferd/recon", tag: "2.4.0"}, - {:quack, "~> 0.1.1"} + {:quack, "~> 0.1.1"}, + {:quantum, "~> 2.3"} ] ++ oauth_deps end diff --git a/mix.lock b/mix.lock index d494cc82d..6e322240a 100644 --- a/mix.lock +++ b/mix.lock @@ -3,23 +3,24 @@ "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "90613b4bae875a3610c275b7056b61ffdd53210d", [ref: "90613b4bae875a3610c275b7056b61ffdd53210d"]}, "base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, - "cachex": {:hex, :cachex, "3.0.2", "1351caa4e26e29f7d7ec1d29b53d6013f0447630bbf382b4fb5d5bad0209f203", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"}, - "calendar": {:hex, :calendar, "0.17.4", "22c5e8d98a4db9494396e5727108dffb820ee0d18fed4b0aa8ab76e4f5bc32f1", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, + "cachex": {:hex, :cachex, "3.0.3", "4e2d3e05814a5738f5ff3903151d5c25636d72a3527251b753f501ad9c657967", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"}, + "calendar": {:hex, :calendar, "0.17.5", "0ff5b09a60b9677683aa2a6fee948558660501c74a289103ea099806bc41a352", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"}, - "comeonin": {:hex, :comeonin, "4.1.1", "c7304fc29b45b897b34142a91122bc72757bc0c295e9e824999d5179ffc08416", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"}, + "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "cowboy": {:hex, :cowboy, "2.6.1", "f2e06f757c337b3b311f9437e6e072b678fcd71545a7b2865bdaa154d078593f", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, - "cowlib": {:hex, :cowlib, "2.7.0", "3ef16e77562f9855a2605900cedb15c1462d76fb1be6a32fc3ae91973ee543d2", [:rebar3], [], "hexpm"}, + "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, + "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"}, "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, + "crontab": {:hex, :crontab, "1.1.5", "2c9439506ceb0e9045de75879e994b88d6f0be88bfe017d58cb356c66c4a5482", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, - "db_connection": {:hex, :db_connection, "2.0.5", "ddb2ba6761a08b2bb9ca0e7d260e8f4dd39067426d835c24491a321b7f92a4da", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, + "db_connection": {:hex, :db_connection, "2.0.6", "bde2f85d047969c5b5800cb8f4b3ed6316c8cb11487afedac4aa5f93fd39abfa", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"}, - "ecto": {:hex, :ecto, "3.0.7", "44dda84ac6b17bbbdeb8ac5dfef08b7da253b37a453c34ab1a98de7f7e5fec7f", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto": {:hex, :ecto, "3.0.8", "9eb6a1fcfc593e6619d45ef51afe607f1554c21ca188a1cd48eecc27223567f1", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, "ecto_sql": {:hex, :ecto_sql, "3.0.5", "7e44172b4f7aca4469f38d7f6a3da394dbf43a1bcf0ca975e958cb957becd74e", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.6", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, - "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, + "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"}, "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, @@ -27,57 +28,61 @@ "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.13.0", "11f08504c4bdd831dc520b8f84a1dce5ce624474a797394e7aafd3c29f5dcd25", [:rebar3], [], "hexpm"}, - "gettext": {:hex, :gettext, "0.15.0", "40a2b8ce33a80ced7727e36768499fc9286881c43ebafccae6bab731e2b2b8ce", [:mix], [], "hexpm"}, + "gen_stage": {:hex, :gen_stage, "0.14.1", "9d46723fda072d4f4bb31a102560013f7960f5d80ea44dcb96fd6304ed61e7a4", [:mix], [], "hexpm"}, + "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, + "gettext": {:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2", [:mix], [], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, + "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, + "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, - "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"}, - "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, + "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, + "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, - "phoenix": {:hex, :phoenix, "1.4.1", "801f9d632808657f1f7c657c8bbe624caaf2ba91429123ebe3801598aea4c3d9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, + "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"}, + "phoenix": {:hex, :phoenix, "1.4.3", "8eed4a64ff1e12372cd634724bddd69185938f52c18e1396ebac76375d85677d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"}, + "phoenix_html": {:hex, :phoenix_html, "2.13.2", "f5d27c9b10ce881a60177d2b5227314fc60881e6b66b41dfe3349db6ed06cf57", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.0.2", "6055f16868cc4882b24b6e1d63d2bada94fb4978413377a3b32ac16c18dffba2", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, - "postgrex": {:hex, :postgrex, "0.14.1", "63247d4a5ad6b9de57a0bac5d807e1c32d41e39c04b8a4156a26c63bcd8a2e49", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "postgrex": {:hex, :postgrex, "0.14.2", "6680591bbce28d92f043249205e8b01b36cab9ef2a7911abc43649242e1a3b78", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.2.2", "a830e77b79dc6d28183f4db050a7cac926a6c58f1872f9ef94a35cd989aceef8", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.2.1", "964a74dfbc055f781d3a75631e06ce3816a2913976d1df7830283aa3118a797a", [:mix], [{:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, - "prometheus_process_collector": {:hex, :prometheus_process_collector, "1.4.0", "6dbd39e3165b9ef1c94a7a820e9ffe08479f949dcdd431ed4aaea7b250eebfde", [:rebar3], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, + "prometheus_process_collector": {:hex, :prometheus_process_collector, "1.4.3", "657386e8f142fc817347d95c1f3a05ab08710f7df9e7f86db6facaed107ed929", [:rebar3], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm"}, + "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, - "swoosh": {:hex, :swoosh, "0.20.0", "9a6c13822c9815993c03b6f8fccc370fcffb3c158d9754f67b1fdee6b3a5d928", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.12", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"}, + "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, + "swoosh": {:hex, :swoosh, "0.23.1", "209b7cc6d862c09d2a064c16caa4d4d1c9c936285476459e16591e0065f8432b", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.12", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, "telemetry": {:hex, :telemetry, "0.3.0", "099a7f3ce31e4780f971b4630a3c22ec66d22208bc090fe33a2a3a6a67754a73", [:rebar3], [], "hexpm"}, "tesla": {:hex, :tesla, "1.2.1", "864783cc27f71dd8c8969163704752476cec0f3a51eb3b06393b3971dc9733ff", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, "timex": {:hex, :timex, "3.5.0", "b0a23167da02d0fe4f1a4e104d1f929a00d348502b52432c05de875d0b9cffa5", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "tzdata": {:hex, :tzdata, "0.5.17", "50793e3d85af49736701da1a040c415c97dc1caf6464112fd9bd18f425d3053b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "tzdata": {:hex, :tzdata, "0.5.20", "304b9e98a02840fb32a43ec111ffbe517863c8566eb04a061f1c4dbb90b4d84c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, - "unsafe": {:hex, :unsafe, "1.0.0", "7c21742cd05380c7875546b023481d3a26f52df8e5dfedcb9f958f322baae305", [:mix], [], "hexpm"}, + "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"}, "web_push_encryption": {:hex, :web_push_encryption, "0.2.1", "d42cecf73420d9dc0053ba3299cc8c8d6ff2be2487d67ca2a57265868e4d9a98", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, } diff --git a/test/notification_test.exs b/test/notification_test.exs index 907b9e669..27d8cace7 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -4,12 +4,15 @@ defmodule Pleroma.NotificationTest do use Pleroma.DataCase + + import Pleroma.Factory + import Mock + alias Pleroma.Notification alias Pleroma.User alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.CommonAPI alias Pleroma.Web.TwitterAPI.TwitterAPI - import Pleroma.Factory describe "create_notifications" do test "notifies someone when they are directly addressed" do @@ -312,16 +315,19 @@ test "Updates `updated_at` field" do }) end) - Process.sleep(1000) - [notification | _] = Notification.for_user(user2) - Notification.set_read_up_to(user2, notification.id) + utc_now = NaiveDateTime.utc_now() + future = NaiveDateTime.add(utc_now, 5, :second) - Notification.for_user(user2) - |> Enum.each(fn notification -> - assert notification.updated_at > notification.inserted_at - end) + with_mock NaiveDateTime, utc_now: fn -> future end do + Notification.set_read_up_to(user2, notification.id) + + Notification.for_user(user2) + |> Enum.each(fn notification -> + assert notification.updated_at > notification.inserted_at + end) + end end end From aeafa0b2ef996f15f9ff4a6ade70a693b12b208f Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 19 Apr 2019 22:16:17 +0700 Subject: [PATCH 004/202] Add Notification.for_user_since/2 --- config/config.exs | 1 + lib/pleroma/notification.ex | 21 +++++++++++++++++ test/notification_test.exs | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/config/config.exs b/config/config.exs index 747d33884..c452b728b 100644 --- a/config/config.exs +++ b/config/config.exs @@ -467,6 +467,7 @@ config :pleroma, :email_notifications, digest: %{ # When to send digest email, in crontab format (https://en.wikipedia.org/wiki/Cron) + # 0 0 * * 0 - once a week at midnight on Sunday morning schedule: "0 0 * * 0", # Minimum interval between digest emails to one user interval: 7, diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 29845b9da..d79f0f563 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -17,6 +17,8 @@ defmodule Pleroma.Notification do import Ecto.Query import Ecto.Changeset + @type t :: %__MODULE__{} + schema "notifications" do field(:seen, :boolean, default: false) belongs_to(:user, User, type: Pleroma.FlakeId) @@ -51,6 +53,25 @@ def for_user(user, opts \\ %{}) do |> Pagination.fetch_paginated(opts) end + @doc """ + Returns notifications for user received since given date. + + ## Examples + + iex> Pleroma.Notification.for_user_since(%Pleroma.User{}, ~N[2019-04-13 11:22:33]) + [%Pleroma.Notification{}, %Pleroma.Notification{}] + + iex> Pleroma.Notification.for_user_since(%Pleroma.User{}, ~N[2019-04-15 11:22:33]) + [] + """ + @spec for_user_since(Pleroma.User.t(), NaiveDateTime.t()) :: [t()] + def for_user_since(user, date) do + from(n in for_user_query(user), + where: n.updated_at > ^date + ) + |> Repo.all() + end + def set_read_up_to(%{id: user_id} = _user, id) do query = from( diff --git a/test/notification_test.exs b/test/notification_test.exs index 27d8cace7..dbc4f48f6 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -331,6 +331,51 @@ test "Updates `updated_at` field" do end end + describe "for_user_since/2" do + defp days_ago(days) do + NaiveDateTime.add( + NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), + -days * 60 * 60 * 24, + :second + ) + end + + test "Returns recent notifications" do + user1 = insert(:user) + user2 = insert(:user) + + Enum.each(0..10, fn i -> + {:ok, _activity} = + CommonAPI.post(user1, %{ + "status" => "hey ##{i} @#{user2.nickname}!" + }) + end) + + {old, new} = Enum.split(Notification.for_user(user2), 5) + + Enum.each(old, fn notification -> + notification + |> cast(%{updated_at: days_ago(10)}, [:updated_at]) + |> Pleroma.Repo.update!() + end) + + recent_notifications_ids = + user2 + |> Notification.for_user_since( + NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86400, :second) + ) + |> Enum.map(& &1.id) + + Enum.each(old, fn %{id: id} -> + refute id in recent_notifications_ids + end) + + Enum.each(new, fn %{id: id} -> + assert id in recent_notifications_ids + end) + end + end + describe "notification target determination" do test "it sends notifications to addressed users in new messages" do user = insert(:user) From 8add1194448cfc183dce01b86451422195d44023 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 19 Apr 2019 22:17:54 +0700 Subject: [PATCH 005/202] Add User.list_inactive_users_query/1 --- lib/pleroma/user.ex | 38 +++++++ ...d_signin_and_last_digest_dates_to_user.exs | 9 ++ test/user_test.exs | 103 ++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 priv/repo/migrations/20190413085040_add_signin_and_last_digest_dates_to_user.exs diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 0982f6ed8..c67a7b7a1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1447,4 +1447,42 @@ defp paginate(query, page, page_size) do def showing_reblogs?(%User{} = user, %User{} = target) do target.ap_id not in user.info.muted_reblogs end + + @doc """ + The function returns a query to get users with no activity for given interval of days. + Inactive users are those who didn't read any notification, or had any activity where + the user is the activity's actor, during `inactivity_threshold` days. + Deactivated users will not appear in this list. + + ## Examples + + iex> Pleroma.User.list_inactive_users() + %Ecto.Query{} + """ + @spec list_inactive_users_query(integer()) :: Ecto.Query.t() + def list_inactive_users_query(inactivity_threshold \\ 7) do + negative_inactivity_threshold = -inactivity_threshold + now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + # Subqueries are not supported in `where` clauses, join gets too complicated. + has_read_notifications = + from(n in Pleroma.Notification, + where: n.seen == true, + group_by: n.id, + having: max(n.updated_at) > datetime_add(^now, ^negative_inactivity_threshold, "day"), + select: n.user_id + ) + |> Pleroma.Repo.all() + + from(u in Pleroma.User, + left_join: a in Pleroma.Activity, + on: u.ap_id == a.actor, + where: not is_nil(u.nickname), + where: fragment("not (?->'deactivated' @> 'true')", u.info), + where: u.id not in ^has_read_notifications, + group_by: u.id, + having: + max(a.inserted_at) < datetime_add(^now, ^negative_inactivity_threshold, "day") or + is_nil(max(a.inserted_at)) + ) + end end diff --git a/priv/repo/migrations/20190413085040_add_signin_and_last_digest_dates_to_user.exs b/priv/repo/migrations/20190413085040_add_signin_and_last_digest_dates_to_user.exs new file mode 100644 index 000000000..4312b171f --- /dev/null +++ b/priv/repo/migrations/20190413085040_add_signin_and_last_digest_dates_to_user.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddSigninAndLastDigestDatesToUser do + use Ecto.Migration + + def change do + alter table(:users) do + add(:last_digest_emailed_at, :naive_datetime, default: fragment("now()")) + end + end +end diff --git a/test/user_test.exs b/test/user_test.exs index d2167a970..ba02997dc 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1167,4 +1167,107 @@ test "follower count is updated when a follower is blocked" do assert Map.get(user_show, "followers_count") == 2 end + + describe "list_inactive_users_query/1" do + defp days_ago(days) do + NaiveDateTime.add( + NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), + -days * 60 * 60 * 24, + :second + ) + end + + test "Users are inactive by default" do + total = 10 + + users = + Enum.map(1..total, fn _ -> + insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + end) + + inactive_users_ids = + Pleroma.User.list_inactive_users_query() + |> Pleroma.Repo.all() + |> Enum.map(& &1.id) + + Enum.each(users, fn user -> + assert user.id in inactive_users_ids + end) + end + + test "Only includes users who has no recent activity" do + total = 10 + + users = + Enum.map(1..total, fn _ -> + insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + end) + + {inactive, active} = Enum.split(users, trunc(total / 2)) + + Enum.map(active, fn user -> + to = Enum.random(users -- [user]) + + {:ok, _} = + Pleroma.Web.TwitterAPI.TwitterAPI.create_status(user, %{ + "status" => "hey @#{to.nickname}" + }) + end) + + inactive_users_ids = + Pleroma.User.list_inactive_users_query() + |> Pleroma.Repo.all() + |> Enum.map(& &1.id) + + Enum.each(active, fn user -> + refute user.id in inactive_users_ids + end) + + Enum.each(inactive, fn user -> + assert user.id in inactive_users_ids + end) + end + + test "Only includes users with no read notifications" do + total = 10 + + users = + Enum.map(1..total, fn _ -> + insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false}) + end) + + [sender | recipients] = users + {inactive, active} = Enum.split(recipients, trunc(total / 2)) + + Enum.each(recipients, fn to -> + {:ok, _} = + Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{ + "status" => "hey @#{to.nickname}" + }) + + {:ok, _} = + Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{ + "status" => "hey again @#{to.nickname}" + }) + end) + + Enum.each(active, fn user -> + [n1, _n2] = Pleroma.Notification.for_user(user) + {:ok, _} = Pleroma.Notification.read_one(user, n1.id) + end) + + inactive_users_ids = + Pleroma.User.list_inactive_users_query() + |> Pleroma.Repo.all() + |> Enum.map(& &1.id) + + Enum.each(active, fn user -> + refute user.id in inactive_users_ids + end) + + Enum.each(inactive, fn user -> + assert user.id in inactive_users_ids + end) + end + end end From bc7862106d9881f858a58319e9e4b44cba1bcf01 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 19 Apr 2019 23:26:41 +0700 Subject: [PATCH 006/202] Fix tests --- lib/pleroma/user.ex | 1 - test/notification_test.exs | 27 --------------------------- test/support/builders/user_builder.ex | 3 ++- test/support/factory.ex | 3 ++- 4 files changed, 4 insertions(+), 30 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c67a7b7a1..7053dfaf3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -55,7 +55,6 @@ defmodule Pleroma.User do field(:tags, {:array, :string}, default: []) field(:bookmarks, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime_usec) - field(:current_sign_in_at, :naive_datetime) field(:last_digest_emailed_at, :naive_datetime) has_many(:notifications, Notification) has_many(:registrations, Registration) diff --git a/test/notification_test.exs b/test/notification_test.exs index dbc4f48f6..462398d75 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.NotificationTest do use Pleroma.DataCase import Pleroma.Factory - import Mock alias Pleroma.Notification alias Pleroma.User @@ -303,32 +302,6 @@ test "it sets all notifications as read up to a specified notification ID" do assert n2.seen == true assert n3.seen == false end - - test "Updates `updated_at` field" do - user1 = insert(:user) - user2 = insert(:user) - - Enum.each(0..10, fn i -> - {:ok, _activity} = - TwitterAPI.create_status(user1, %{ - "status" => "#{i} hi @#{user2.nickname}" - }) - end) - - [notification | _] = Notification.for_user(user2) - - utc_now = NaiveDateTime.utc_now() - future = NaiveDateTime.add(utc_now, 5, :second) - - with_mock NaiveDateTime, utc_now: fn -> future end do - Notification.set_read_up_to(user2, notification.id) - - Notification.for_user(user2) - |> Enum.each(fn notification -> - assert notification.updated_at > notification.inserted_at - end) - end - end end describe "for_user_since/2" do diff --git a/test/support/builders/user_builder.ex b/test/support/builders/user_builder.ex index f58e1b0ad..6da16f71a 100644 --- a/test/support/builders/user_builder.ex +++ b/test/support/builders/user_builder.ex @@ -9,7 +9,8 @@ def build(data \\ %{}) do nickname: "testname", password_hash: Comeonin.Pbkdf2.hashpwsalt("test"), bio: "A tester.", - ap_id: "some id" + ap_id: "some id", + last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) } Map.merge(user, data) diff --git a/test/support/factory.ex b/test/support/factory.ex index ea59912cf..0840f31ec 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -12,7 +12,8 @@ def user_factory do nickname: sequence(:nickname, &"nick#{&1}"), password_hash: Comeonin.Pbkdf2.hashpwsalt("test"), bio: sequence(:bio, &"Tester Number #{&1}"), - info: %{} + info: %{}, + last_digest_emailed_at: NaiveDateTime.utc_now() } %{ From 64a2c6a041ca62ad84b1d682ef56fbca45e44de5 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sat, 20 Apr 2019 19:42:19 +0700 Subject: [PATCH 007/202] Digest emails --- config/config.exs | 2 + lib/mix/tasks/pleroma/instance.ex | 2 + lib/mix/tasks/pleroma/sample_config.eex | 2 + lib/pleroma/application.ex | 22 ++++++- lib/pleroma/digest_email_worker.ex | 45 ++++++++++++++ lib/pleroma/emails/user_email.ex | 59 ++++++++++++++++++- lib/pleroma/jwt.ex | 9 +++ lib/pleroma/quantum_scheduler.ex | 4 ++ lib/pleroma/user.ex | 36 +++++++++++ .../web/mailer/subscription_controller.ex | 18 ++++++ lib/pleroma/web/router.ex | 2 + .../web/templates/email/digest.html.eex | 20 +++++++ .../web/templates/layout/email.html.eex | 10 ++++ .../subscription/unsubscribe_failure.html.eex | 1 + .../subscription/unsubscribe_success.html.eex | 1 + lib/pleroma/web/views/email_view.ex | 5 ++ .../web/views/mailer/subscription_view.ex | 3 + mix.exs | 4 +- mix.lock | 2 + 19 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 lib/pleroma/digest_email_worker.ex create mode 100644 lib/pleroma/jwt.ex create mode 100644 lib/pleroma/quantum_scheduler.ex create mode 100644 lib/pleroma/web/mailer/subscription_controller.ex create mode 100644 lib/pleroma/web/templates/email/digest.html.eex create mode 100644 lib/pleroma/web/templates/layout/email.html.eex create mode 100644 lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex create mode 100644 lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex create mode 100644 lib/pleroma/web/views/email_view.ex create mode 100644 lib/pleroma/web/views/mailer/subscription_view.ex diff --git a/config/config.exs b/config/config.exs index 25dc91eb1..2663b1ebd 100644 --- a/config/config.exs +++ b/config/config.exs @@ -468,6 +468,8 @@ config :pleroma, :email_notifications, digest: %{ + # Globally enable or disable digest emails + active: true, # When to send digest email, in crontab format (https://en.wikipedia.org/wiki/Cron) # 0 0 * * 0 - once a week at midnight on Sunday morning schedule: "0 0 * * 0", diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 6cee8d630..d276df93a 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -125,6 +125,7 @@ def run(["gen" | rest]) do ) secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64) + jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64) signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8) {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1) @@ -142,6 +143,7 @@ def run(["gen" | rest]) do dbpass: dbpass, version: Pleroma.Mixfile.project() |> Keyword.get(:version), secret: secret, + jwt_secret: jwt_secret, signing_salt: signing_salt, web_push_public_key: Base.url_encode64(web_push_public_key, padding: false), web_push_private_key: Base.url_encode64(web_push_private_key, padding: false) diff --git a/lib/mix/tasks/pleroma/sample_config.eex b/lib/mix/tasks/pleroma/sample_config.eex index 52bd57cb7..ec7d8821e 100644 --- a/lib/mix/tasks/pleroma/sample_config.eex +++ b/lib/mix/tasks/pleroma/sample_config.eex @@ -76,3 +76,5 @@ config :web_push_encryption, :vapid_details, # storage_url: "https://swift-endpoint.prodider.com/v1/AUTH_/", # object_url: "https://cdn-endpoint.provider.com/" # + +config :joken, default_signer: "<%= jwt_secret %>" diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index eeb415084..76f8d9bcd 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -105,7 +105,8 @@ def start(_type, _args) do id: :cachex_idem ), worker(Pleroma.FlakeId, []), - worker(Pleroma.ScheduledActivityWorker, []) + worker(Pleroma.ScheduledActivityWorker, []), + worker(Pleroma.QuantumScheduler, []) ] ++ hackney_pool_children() ++ [ @@ -125,7 +126,9 @@ def start(_type, _args) do # 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) + result = Supervisor.start_link(children, opts) + :ok = after_supervisor_start() + result end defp setup_instrumenters do @@ -183,4 +186,19 @@ defp hackney_pool_children do :hackney_pool.child_spec(pool, options) end end + + defp after_supervisor_start() do + with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], + true <- digest_config[:active], + %Crontab.CronExpression{} = schedule <- + Crontab.CronExpression.Parser.parse!(digest_config[:schedule]) do + Pleroma.QuantumScheduler.new_job() + |> Quantum.Job.set_name(:digest_emails) + |> Quantum.Job.set_schedule(schedule) + |> Quantum.Job.set_task(&Pleroma.DigestEmailWorker.run/0) + |> Pleroma.QuantumScheduler.add_job() + end + + :ok + end end diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex new file mode 100644 index 000000000..fa6067a03 --- /dev/null +++ b/lib/pleroma/digest_email_worker.ex @@ -0,0 +1,45 @@ +defmodule Pleroma.DigestEmailWorker do + import Ecto.Query + require Logger + + # alias Pleroma.User + + def run() do + Logger.warn("Running digester") + config = Application.get_env(:pleroma, :email_notifications)[:digest] + negative_interval = -Map.fetch!(config, :interval) + inactivity_threshold = Map.fetch!(config, :inactivity_threshold) + inactive_users_query = Pleroma.User.list_inactive_users_query(inactivity_threshold) + + now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + + from(u in inactive_users_query, + where: fragment("? #> '{\"email_notifications\",\"digest\"}' @> 'true'", u.info), + where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), + select: u + ) + |> Pleroma.Repo.all() + |> run(:pre) + end + + defp run(v, :pre) do + Logger.warn("Running for #{length(v)} users") + run(v) + end + + defp run([]), do: :ok + + defp run([user | users]) do + with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(user) do + Logger.warn("Sending to #{user.nickname}") + Pleroma.Emails.Mailer.deliver_async(email) + else + _ -> + Logger.warn("Skipping #{user.nickname}") + end + + Pleroma.User.touch_last_digest_emailed_at(user) + + run(users) + end +end diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 8502a0d0c..64f855112 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Emails.UserEmail do @moduledoc "User emails" - import Swoosh.Email + use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email} alias Pleroma.Web.Endpoint alias Pleroma.Web.Router @@ -92,4 +92,61 @@ def account_confirmation_email(user) do |> subject("#{instance_name()} account confirmation") |> html_body(html_body) end + + @doc """ + Email used in digest email notifications + Includes Mentions and New Followers data + If there are no mentions (even when new followers exist), the function will return nil + """ + @spec digest_email(Pleroma.User.t()) :: Swoosh.Email.t() | nil + def digest_email(user) do + new_notifications = + Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at) + |> Enum.reduce(%{followers: [], mentions: []}, fn + %{activity: %{data: %{"type" => "Create"}, actor: actor}} = notification, acc -> + new_mention = %{data: notification, from: Pleroma.User.get_by_ap_id(actor)} + %{acc | mentions: [new_mention | acc.mentions]} + + %{activity: %{data: %{"type" => "Follow"}, actor: actor}} = notification, acc -> + new_follower = %{data: notification, from: Pleroma.User.get_by_ap_id(actor)} + %{acc | followers: [new_follower | acc.followers]} + + _, acc -> + acc + end) + + with [_ | _] = mentions <- new_notifications.mentions do + html_data = %{ + instance: instance_name(), + user: user, + mentions: mentions, + followers: new_notifications.followers, + unsubscribe_link: unsubscribe_url(user, "digest") + } + + new() + |> to(recipient(user)) + |> from(sender()) + |> subject("Your digest from #{instance_name()}") + |> render_body("digest.html", html_data) + else + _ -> + nil + end + end + + @doc """ + Generate unsubscribe link for given user and notifications type. + The link contains JWT token with the data, and subscription can be modified without + authorization. + """ + @spec unsubscribe_url(Pleroma.User.t(), String.t()) :: String.t() + def unsubscribe_url(user, notifications_type) do + token = + %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false} + |> Pleroma.JWT.generate_and_sign!() + |> Base.encode64() + + Router.Helpers.subscription_url(Pleroma.Web.Endpoint, :unsubscribe, token) + end end diff --git a/lib/pleroma/jwt.ex b/lib/pleroma/jwt.ex new file mode 100644 index 000000000..10102ff5d --- /dev/null +++ b/lib/pleroma/jwt.ex @@ -0,0 +1,9 @@ +defmodule Pleroma.JWT do + use Joken.Config + + @impl true + def token_config do + default_claims(skip: [:aud]) + |> add_claim("aud", &Pleroma.Web.Endpoint.url/0, &(&1 == Pleroma.Web.Endpoint.url())) + end +end diff --git a/lib/pleroma/quantum_scheduler.ex b/lib/pleroma/quantum_scheduler.ex new file mode 100644 index 000000000..9a3df81f6 --- /dev/null +++ b/lib/pleroma/quantum_scheduler.ex @@ -0,0 +1,4 @@ +defmodule Pleroma.QuantumScheduler do + use Quantum.Scheduler, + otp_app: :pleroma +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7053dfaf3..2509d2366 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1484,4 +1484,40 @@ def list_inactive_users_query(inactivity_threshold \\ 7) do is_nil(max(a.inserted_at)) ) end + + @doc """ + Enable or disable email notifications for user + + ## Examples + + iex> Pleroma.User.switch_email_notifications(Pleroma.User{info: %{email_notifications: %{"digest" => false}}}, "digest", true) + Pleroma.User{info: %{email_notifications: %{"digest" => true}}} + + iex> Pleroma.User.switch_email_notifications(Pleroma.User{info: %{email_notifications: %{"digest" => true}}}, "digest", false) + Pleroma.User{info: %{email_notifications: %{"digest" => false}}} + """ + @spec switch_email_notifications(t(), String.t(), boolean()) :: + {:ok, t()} | {:error, Ecto.Changeset.t()} + def switch_email_notifications(user, type, status) do + info = Pleroma.User.Info.update_email_notifications(user.info, %{type => status}) + + change(user) + |> put_embed(:info, info) + |> update_and_set_cache() + end + + @doc """ + Set `last_digest_emailed_at` value for the user to current time + """ + @spec touch_last_digest_emailed_at(t()) :: t() + def touch_last_digest_emailed_at(user) do + now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + + {:ok, updated_user} = + user + |> change(%{last_digest_emailed_at: now}) + |> update_and_set_cache() + + updated_user + end end diff --git a/lib/pleroma/web/mailer/subscription_controller.ex b/lib/pleroma/web/mailer/subscription_controller.ex new file mode 100644 index 000000000..2334ebacb --- /dev/null +++ b/lib/pleroma/web/mailer/subscription_controller.ex @@ -0,0 +1,18 @@ +defmodule Pleroma.Web.Mailer.SubscriptionController do + use Pleroma.Web, :controller + + alias Pleroma.{JWT, Repo, User} + + def unsubscribe(conn, %{"token" => encoded_token}) do + with {:ok, token} <- Base.decode64(encoded_token), + {:ok, claims} <- JWT.verify_and_validate(token), + %{"act" => %{"unsubscribe" => type}, "sub" => uid} <- claims, + %User{} = user <- Repo.get(User, uid), + {:ok, _user} <- User.switch_email_notifications(user, type, false) do + render(conn, "unsubscribe_success.html", email: user.email) + else + _err -> + render(conn, "unsubscribe_failure.html") + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8b665d61b..09e51e602 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -562,6 +562,8 @@ defmodule Pleroma.Web.Router do post("/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request) get("/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation) post("/push/subscriptions/:id", Websub.WebsubController, :websub_incoming) + + get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe) end scope "/", Pleroma.Web do diff --git a/lib/pleroma/web/templates/email/digest.html.eex b/lib/pleroma/web/templates/email/digest.html.eex new file mode 100644 index 000000000..93c9c884f --- /dev/null +++ b/lib/pleroma/web/templates/email/digest.html.eex @@ -0,0 +1,20 @@ +

Hey <%= @user.nickname %>, here is what you've missed!

+ +

New Mentions:

+
    +<%= for %{data: mention, from: from} <- @mentions do %> +
  • <%= link from.nickname, to: mention.activity.actor %>: <%= raw mention.activity.object.data["content"] %>
  • +<% end %> +
+ +<%= if @followers != [] do %> +

<%= length(@followers) %> New Followers:

+
    +<%= for %{data: follow, from: from} <- @followers do %> +
  • <%= link from.nickname, to: follow.activity.actor %>
  • +<% end %> +
+<% end %> + +

You have received this email because you have signed up to receive digest emails from <%= @instance %> Pleroma instance.

+

The email address you are subscribed as is <%= @user.email %>. To unsubscribe, please go <%= link "here", to: @unsubscribe_link %>.

\ No newline at end of file diff --git a/lib/pleroma/web/templates/layout/email.html.eex b/lib/pleroma/web/templates/layout/email.html.eex new file mode 100644 index 000000000..f6dcd7f0f --- /dev/null +++ b/lib/pleroma/web/templates/layout/email.html.eex @@ -0,0 +1,10 @@ + + + + + <%= @email.subject %> + + + <%= render @view_module, @view_template, assigns %> + + \ No newline at end of file diff --git a/lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex b/lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex new file mode 100644 index 000000000..7b476f02d --- /dev/null +++ b/lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex @@ -0,0 +1 @@ +

UNSUBSCRIBE FAILURE

diff --git a/lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex b/lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex new file mode 100644 index 000000000..6dfa2c185 --- /dev/null +++ b/lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex @@ -0,0 +1 @@ +

UNSUBSCRIBE SUCCESSFUL

diff --git a/lib/pleroma/web/views/email_view.ex b/lib/pleroma/web/views/email_view.ex new file mode 100644 index 000000000..b63eb162c --- /dev/null +++ b/lib/pleroma/web/views/email_view.ex @@ -0,0 +1,5 @@ +defmodule Pleroma.Web.EmailView do + use Pleroma.Web, :view + import Phoenix.HTML + import Phoenix.HTML.Link +end diff --git a/lib/pleroma/web/views/mailer/subscription_view.ex b/lib/pleroma/web/views/mailer/subscription_view.ex new file mode 100644 index 000000000..fc3d20816 --- /dev/null +++ b/lib/pleroma/web/views/mailer/subscription_view.ex @@ -0,0 +1,3 @@ +defmodule Pleroma.Web.Mailer.SubscriptionView do + use Pleroma.Web, :view +end diff --git a/mix.exs b/mix.exs index da2e284f8..6bb105538 100644 --- a/mix.exs +++ b/mix.exs @@ -93,6 +93,7 @@ defp deps do {:ex_doc, "~> 0.20.2", only: :dev, runtime: false}, {:web_push_encryption, "~> 0.2.1"}, {:swoosh, "~> 0.20"}, + {:phoenix_swoosh, "~> 0.2"}, {:gen_smtp, "~> 0.13"}, {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}, {:floki, "~> 0.20.0"}, @@ -111,7 +112,8 @@ defp deps do {:prometheus_process_collector, "~> 1.4"}, {:recon, github: "ferd/recon", tag: "2.4.0"}, {:quack, "~> 0.1.1"}, - {:quantum, "~> 2.3"} + {:quantum, "~> 2.3"}, + {:joken, "~> 2.0"} ] ++ oauth_deps end diff --git a/mix.lock b/mix.lock index 6e322240a..73aed012f 100644 --- a/mix.lock +++ b/mix.lock @@ -37,6 +37,7 @@ "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, + "joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, @@ -55,6 +56,7 @@ "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.2", "f5d27c9b10ce881a60177d2b5227314fc60881e6b66b41dfe3349db6ed06cf57", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, + "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.2", "6055f16868cc4882b24b6e1d63d2bada94fb4978413377a3b32ac16c18dffba2", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, From 05cdb2f2389376081973d96b32e876d2a032d1f1 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sat, 20 Apr 2019 19:42:50 +0700 Subject: [PATCH 008/202] Do not track coverage files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 774893b35..8166e65e9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ erl_crash.dump # Prevent committing docs files /priv/static/doc/* + +/cover From 724311e15177a1a97f533f11ff17d8d0146800ef Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sat, 20 Apr 2019 19:57:43 +0700 Subject: [PATCH 009/202] Fix Credo warnings --- lib/pleroma/application.ex | 2 +- lib/pleroma/digest_email_worker.ex | 4 ++-- lib/pleroma/web/mailer/subscription_controller.ex | 4 +++- mix.exs | 2 +- test/notification_test.exs | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 76f8d9bcd..299f8807b 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -187,7 +187,7 @@ defp hackney_pool_children do end end - defp after_supervisor_start() do + defp after_supervisor_start do with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], true <- digest_config[:active], %Crontab.CronExpression{} = schedule <- diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index fa6067a03..7be470f5f 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -4,7 +4,7 @@ defmodule Pleroma.DigestEmailWorker do # alias Pleroma.User - def run() do + def run do Logger.warn("Running digester") config = Application.get_env(:pleroma, :email_notifications)[:digest] negative_interval = -Map.fetch!(config, :interval) @@ -14,7 +14,7 @@ def run() do now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) from(u in inactive_users_query, - where: fragment("? #> '{\"email_notifications\",\"digest\"}' @> 'true'", u.info), + where: fragment(~s(? #> '{"email_notifications","digest"}' @> 'true'), u.info), where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), select: u ) diff --git a/lib/pleroma/web/mailer/subscription_controller.ex b/lib/pleroma/web/mailer/subscription_controller.ex index 2334ebacb..478a83518 100644 --- a/lib/pleroma/web/mailer/subscription_controller.ex +++ b/lib/pleroma/web/mailer/subscription_controller.ex @@ -1,7 +1,9 @@ defmodule Pleroma.Web.Mailer.SubscriptionController do use Pleroma.Web, :controller - alias Pleroma.{JWT, Repo, User} + alias Pleroma.JWT + alias Pleroma.Repo + alias Pleroma.User def unsubscribe(conn, %{"token" => encoded_token}) do with {:ok, token} <- Base.decode64(encoded_token), diff --git a/mix.exs b/mix.exs index 6bb105538..2cdfb1392 100644 --- a/mix.exs +++ b/mix.exs @@ -8,7 +8,7 @@ def project do elixir: "~> 1.7", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix, :gettext] ++ Mix.compilers(), - # elixirc_options: [warnings_as_errors: true], + elixirc_options: [warnings_as_errors: true], xref: [exclude: [:eldap]], start_permanent: Mix.env() == :prod, aliases: aliases(), diff --git a/test/notification_test.exs b/test/notification_test.exs index 462398d75..3bbce8fcf 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -335,7 +335,7 @@ test "Returns recent notifications" do recent_notifications_ids = user2 |> Notification.for_user_since( - NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86400, :second) + NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second) ) |> Enum.map(& &1.id) From 2359ee38b38de17df4dfe9cbdfe551bb7d9a034d Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 16:36:25 +0700 Subject: [PATCH 010/202] Set digest emails to false by default --- lib/pleroma/user/info.ex | 2 +- priv/repo/migrations/20190412052952_add_user_info_fields.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 194dd5581..d827293b8 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -42,7 +42,7 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) - field(:email_notifications, :map, default: %{"digest" => true}) + field(:email_notifications, :map, default: %{"digest" => false}) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} diff --git a/priv/repo/migrations/20190412052952_add_user_info_fields.exs b/priv/repo/migrations/20190412052952_add_user_info_fields.exs index 203d0fc3b..646c91f32 100644 --- a/priv/repo/migrations/20190412052952_add_user_info_fields.exs +++ b/priv/repo/migrations/20190412052952_add_user_info_fields.exs @@ -6,7 +6,7 @@ def up do UPDATE users SET info = info || '{ \"email_notifications\": { - \"digest\": true + \"digest\": false } }'") end From f1d90ee94206db00025d41b13a2906aa30d748f0 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 16:40:05 +0700 Subject: [PATCH 011/202] Remove debug code --- lib/pleroma/digest_email_worker.ex | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 7be470f5f..65013f77e 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -1,11 +1,7 @@ defmodule Pleroma.DigestEmailWorker do import Ecto.Query - require Logger - - # alias Pleroma.User def run do - Logger.warn("Running digester") config = Application.get_env(:pleroma, :email_notifications)[:digest] negative_interval = -Map.fetch!(config, :interval) inactivity_threshold = Map.fetch!(config, :inactivity_threshold) @@ -19,23 +15,14 @@ def run do select: u ) |> Pleroma.Repo.all() - |> run(:pre) - end - - defp run(v, :pre) do - Logger.warn("Running for #{length(v)} users") - run(v) + |> run() end defp run([]), do: :ok defp run([user | users]) do with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(user) do - Logger.warn("Sending to #{user.nickname}") Pleroma.Emails.Mailer.deliver_async(email) - else - _ -> - Logger.warn("Skipping #{user.nickname}") end Pleroma.User.touch_last_digest_emailed_at(user) From b87ad13803df59d88feb736c3d0ff9cf514989d7 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 19:36:31 +0700 Subject: [PATCH 012/202] Move comments for email_notifications config to docs --- config/config.exs | 5 ----- docs/config.md | 12 ++++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/config/config.exs b/config/config.exs index 2663b1ebd..b1d506b59 100644 --- a/config/config.exs +++ b/config/config.exs @@ -468,14 +468,9 @@ config :pleroma, :email_notifications, digest: %{ - # Globally enable or disable digest emails active: true, - # When to send digest email, in crontab format (https://en.wikipedia.org/wiki/Cron) - # 0 0 * * 0 - once a week at midnight on Sunday morning schedule: "0 0 * * 0", - # Minimum interval between digest emails to one user interval: 7, - # Minimum user inactivity threshold inactivity_threshold: 7 } diff --git a/docs/config.md b/docs/config.md index 5a97033b2..69d389382 100644 --- a/docs/config.md +++ b/docs/config.md @@ -435,6 +435,18 @@ Authentication / authorization settings. * `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. * `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. +## :email_notifications + +Email notifications settings. + + - digest - emails of "what you've missed" for users who have been + inactive for a while. + - active: globally enable or disable digest emails + - schedule: When to send digest email, in [crontab format](https://en.wikipedia.org/wiki/Cron). + "0 0 * * 0" is the default, meaning "once a week at midnight on Sunday morning" + - interval: Minimum interval between digest emails to one user + - inactivity_threshold: Minimum user inactivity threshold + # OAuth consumer mode OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.). From 5cee2fe9fea4f0c98acd49a2a288ecd44bce3d1f Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Wed, 29 May 2019 21:31:27 +0300 Subject: [PATCH 013/202] Replace Application.get_env/2 with Pleroma.Config.get/1 --- lib/pleroma/digest_email_worker.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 65013f77e..f7b3d81cd 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -2,7 +2,7 @@ defmodule Pleroma.DigestEmailWorker do import Ecto.Query def run do - config = Application.get_env(:pleroma, :email_notifications)[:digest] + config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) inactivity_threshold = Map.fetch!(config, :inactivity_threshold) inactive_users_query = Pleroma.User.list_inactive_users_query(inactivity_threshold) From 3e1761058711b12fa995f2b43117fb90ca40c9ad Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 4 Jun 2019 02:48:21 +0300 Subject: [PATCH 014/202] Add task to test emails --- lib/mix/tasks/pleroma/digest.ex | 34 +++++++++++++++ lib/pleroma/digest_email_worker.ex | 4 +- lib/pleroma/emails/user_email.ex | 20 +++++++-- .../web/templates/email/digest.html.eex | 4 +- test/mix/tasks/pleroma.digest_test.exs | 42 +++++++++++++++++++ 5 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 lib/mix/tasks/pleroma/digest.ex create mode 100644 test/mix/tasks/pleroma.digest_test.exs diff --git a/lib/mix/tasks/pleroma/digest.ex b/lib/mix/tasks/pleroma/digest.ex new file mode 100644 index 000000000..7ac3df5c7 --- /dev/null +++ b/lib/mix/tasks/pleroma/digest.ex @@ -0,0 +1,34 @@ +defmodule Mix.Tasks.Pleroma.Digest do + use Mix.Task + alias Mix.Tasks.Pleroma.Common + + @shortdoc "Manages digest emails" + @moduledoc """ + Manages digest emails + + ## Send digest email since given date (user registration date by default) + ignoring user activity status. + + ``mix pleroma.digest test `` + + Example: ``mix pleroma.digest test donaldtheduck 2019-05-20`` + """ + def run(["test", nickname | opts]) do + Common.start_pleroma() + + user = Pleroma.User.get_by_nickname(nickname) + + last_digest_emailed_at = + with [date] <- opts, + {:ok, datetime} <- Timex.parse(date, "{YYYY}-{0M}-{0D}") do + datetime + else + _ -> user.inserted_at + end + + patched_user = %{user | last_digest_emailed_at: last_digest_emailed_at} + + :ok = Pleroma.DigestEmailWorker.run([patched_user]) + Mix.shell().info("Digest email have been sent to #{nickname} (#{user.email})") + end +end diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index f7b3d81cd..8c28dca18 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -18,9 +18,9 @@ def run do |> run() end - defp run([]), do: :ok + def run([]), do: :ok - defp run([user | users]) do + def run([user | users]) do with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(user) do Pleroma.Emails.Mailer.deliver_async(email) end diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 64f855112..0ad0aed40 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -103,12 +103,24 @@ def digest_email(user) do new_notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at) |> Enum.reduce(%{followers: [], mentions: []}, fn - %{activity: %{data: %{"type" => "Create"}, actor: actor}} = notification, acc -> - new_mention = %{data: notification, from: Pleroma.User.get_by_ap_id(actor)} + %{activity: %{data: %{"type" => "Create"}, actor: actor} = activity} = notification, + acc -> + new_mention = %{ + data: notification, + object: Pleroma.Object.normalize(activity), + from: Pleroma.User.get_by_ap_id(actor) + } + %{acc | mentions: [new_mention | acc.mentions]} - %{activity: %{data: %{"type" => "Follow"}, actor: actor}} = notification, acc -> - new_follower = %{data: notification, from: Pleroma.User.get_by_ap_id(actor)} + %{activity: %{data: %{"type" => "Follow"}, actor: actor} = activity} = notification, + acc -> + new_follower = %{ + data: notification, + object: Pleroma.Object.normalize(activity), + from: Pleroma.User.get_by_ap_id(actor) + } + %{acc | followers: [new_follower | acc.followers]} _, acc -> diff --git a/lib/pleroma/web/templates/email/digest.html.eex b/lib/pleroma/web/templates/email/digest.html.eex index 93c9c884f..c9dd699fd 100644 --- a/lib/pleroma/web/templates/email/digest.html.eex +++ b/lib/pleroma/web/templates/email/digest.html.eex @@ -2,8 +2,8 @@

New Mentions:

    -<%= for %{data: mention, from: from} <- @mentions do %> -
  • <%= link from.nickname, to: mention.activity.actor %>: <%= raw mention.activity.object.data["content"] %>
  • +<%= for %{data: mention, object: object, from: from} <- @mentions do %> +
  • <%= link from.nickname, to: mention.activity.actor %>: <%= raw object.data["content"] %>
  • <% end %>
diff --git a/test/mix/tasks/pleroma.digest_test.exs b/test/mix/tasks/pleroma.digest_test.exs new file mode 100644 index 000000000..1a54ac35b --- /dev/null +++ b/test/mix/tasks/pleroma.digest_test.exs @@ -0,0 +1,42 @@ +defmodule Mix.Tasks.Pleroma.DigestTest do + use Pleroma.DataCase + + import Pleroma.Factory + import Swoosh.TestAssertions + + alias Pleroma.Web.CommonAPI + + setup_all do + Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(Mix.Shell.IO) + end) + + :ok + end + + describe "pleroma.digest test" do + test "Sends digest to the given user" do + user1 = insert(:user) + user2 = insert(:user) + + Enum.each(0..10, fn i -> + {:ok, _activity} = + CommonAPI.post(user1, %{ + "status" => "hey ##{i} @#{user2.nickname}!" + }) + end) + + Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname]) + + assert_email_sent( + to: {user2.name, user2.email}, + html_body: ~r/new mentions:/i + ) + + assert_received {:mix_shell, :info, [message]} + assert message =~ "Digest email have been sent" + end + end +end From bd325132ca337c57f63b6443ae44748d9a422f65 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 4 Jun 2019 03:07:49 +0300 Subject: [PATCH 015/202] Fix tests --- config/test.exs | 2 ++ test/mix/tasks/pleroma.digest_test.exs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/test.exs b/config/test.exs index 41cddb9bd..adb874223 100644 --- a/config/test.exs +++ b/config/test.exs @@ -67,6 +67,8 @@ config :pleroma, :database, rum_enabled: rum_enabled IO.puts("RUM enabled: #{rum_enabled}") +config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp35v0RK9SO8WTPr6QZ" + try do import_config "test.secret.exs" rescue diff --git a/test/mix/tasks/pleroma.digest_test.exs b/test/mix/tasks/pleroma.digest_test.exs index 1a54ac35b..3dafe05fe 100644 --- a/test/mix/tasks/pleroma.digest_test.exs +++ b/test/mix/tasks/pleroma.digest_test.exs @@ -30,13 +30,13 @@ test "Sends digest to the given user" do Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname]) + assert_received {:mix_shell, :info, [message]} + assert message =~ "Digest email have been sent" + assert_email_sent( to: {user2.name, user2.email}, html_body: ~r/new mentions:/i ) - - assert_received {:mix_shell, :info, [message]} - assert message =~ "Digest email have been sent" end end end From 7718a215e9b20471169bf2474771a4fe486a3050 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 4 Jun 2019 03:08:00 +0300 Subject: [PATCH 016/202] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2144bbe28..fef10463a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] ### Added +- Digest email for inactive users - Optional SSH access mode. (Needs `erlang-ssh` package on some distributions). - [MongooseIM](https://github.com/esl/MongooseIM) http authentication support. - LDAP authentication @@ -25,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: `notify_email` option - Configuration: Media proxy `whitelist` option - Configuration: `report_uri` option +- Configuration: `email_notifications` option - Pleroma API: User subscriptions - Pleroma API: Healthcheck endpoint - Pleroma API: `/api/v1/pleroma/mascot` per-user frontend mascot configuration endpoints From f6036ce3b9649902ce1c2af819616ad25f0caef1 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 4 Jun 2019 03:38:53 +0300 Subject: [PATCH 017/202] Fix tests --- test/mix/tasks/pleroma.digest_test.exs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/mix/tasks/pleroma.digest_test.exs b/test/mix/tasks/pleroma.digest_test.exs index 3dafe05fe..595f64ed7 100644 --- a/test/mix/tasks/pleroma.digest_test.exs +++ b/test/mix/tasks/pleroma.digest_test.exs @@ -28,9 +28,18 @@ test "Sends digest to the given user" do }) end) - Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname]) + yesterday = + NaiveDateTime.add( + NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), + -60 * 60 * 24, + :second + ) - assert_received {:mix_shell, :info, [message]} + {:ok, yesterday_date} = Timex.format(yesterday, "%F", :strftime) + + :ok = Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname, yesterday_date]) + + assert_receive {:mix_shell, :info, [message]} assert message =~ "Digest email have been sent" assert_email_sent( From c0fa0001476a8a45878a0c75125627164497eddf Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 7 Jun 2019 01:22:35 +0300 Subject: [PATCH 018/202] Set default config for digest to false --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 5a05ee043..509f4b081 100644 --- a/config/config.exs +++ b/config/config.exs @@ -494,7 +494,7 @@ config :pleroma, :email_notifications, digest: %{ - active: true, + active: false, schedule: "0 0 * * 0", interval: 7, inactivity_threshold: 7 From 0384459ce552c50edb582413808a099086b6495e Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Fri, 12 Jul 2019 18:16:54 +0300 Subject: [PATCH 019/202] Update mix.lock --- mix.lock | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mix.lock b/mix.lock index 654972ddd..a09022acb 100644 --- a/mix.lock +++ b/mix.lock @@ -35,6 +35,8 @@ "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"}, + "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"}, + "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, @@ -83,6 +85,7 @@ "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, From e8fa477793e1395664f79d572800f11994cdd38d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 13 Jul 2019 19:17:57 +0300 Subject: [PATCH 020/202] Refactor Follows/Followers counter syncronization - Actually sync counters in the database instead of info cache (which got overriden after user update was finished anyway) - Add following count field to user info - Set hide_followers/hide_follows for remote users based on http status codes for the first collection page --- config/test.exs | 3 +- lib/pleroma/object/fetcher.ex | 6 ++- lib/pleroma/user.ex | 4 +- lib/pleroma/user/info.ex | 13 ++++- lib/pleroma/web/activity_pub/activity_pub.ex | 53 ++++++++++++++++++- .../web/activity_pub/transmogrifier.ex | 27 ---------- test/web/activity_pub/transmogrifier_test.exs | 28 ---------- 7 files changed, 73 insertions(+), 61 deletions(-) diff --git a/config/test.exs b/config/test.exs index 96ecf3592..28eea3b00 100644 --- a/config/test.exs +++ b/config/test.exs @@ -29,7 +29,8 @@ email: "admin@example.com", notify_email: "noreply@example.com", skip_thread_containment: false, - federating: false + federating: false, + external_user_synchronization: false # Configure your database config :pleroma, Pleroma.Repo, diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 101c21f96..bc3e7e5bc 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -76,7 +76,7 @@ def fetch_object_from_id!(id, options \\ []) do end end - def fetch_and_contain_remote_object_from_id(id) do + def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do Logger.info("Fetching object #{id} via AP") with true <- String.starts_with?(id, "http"), @@ -96,4 +96,8 @@ def fetch_and_contain_remote_object_from_id(id) do {:error, e} end end + + def fetch_and_contain_remote_object_from_id(_id) do + {:error, "id must be a string"} + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e5a6c2529..c252e8bff 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -114,7 +114,9 @@ def ap_following(%User{} = user), do: "#{ap_id(user)}/following" def user_info(%User{} = user, args \\ %{}) do following_count = - if args[:following_count], do: args[:following_count], else: following_count(user) + if args[:following_count], + do: args[:following_count], + else: user.info.following_count || following_count(user) follower_count = if args[:follower_count], do: args[:follower_count], else: user.info.follower_count diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 08e43ff0f..2d8395b73 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -16,6 +16,7 @@ defmodule Pleroma.User.Info do field(:source_data, :map, default: %{}) field(:note_count, :integer, default: 0) field(:follower_count, :integer, default: 0) + field(:following_count, :integer, default: nil) field(:locked, :boolean, default: false) field(:confirmation_pending, :boolean, default: false) field(:confirmation_token, :string, default: nil) @@ -195,7 +196,11 @@ def remote_user_creation(info, params) do :uri, :hub, :topic, - :salmon + :salmon, + :hide_followers, + :hide_follows, + :follower_count, + :following_count ]) end @@ -206,7 +211,11 @@ def user_upgrade(info, params) do :source_data, :banner, :locked, - :magic_key + :magic_key, + :follower_count, + :following_count, + :hide_follows, + :hide_followers ]) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a3174a787..0a22fe223 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1013,6 +1013,56 @@ defp object_to_user_data(data) do {:ok, user_data} end + defp maybe_update_follow_information(data) do + with {:enabled, true} <- + {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, + {:ok, following_data} <- + Fetcher.fetch_and_contain_remote_object_from_id(data.following_address), + following_count <- following_data["totalItems"], + hide_follows <- collection_private?(following_data), + {:ok, followers_data} <- + Fetcher.fetch_and_contain_remote_object_from_id(data.follower_address), + followers_count <- followers_data["totalItems"], + hide_followers <- collection_private?(followers_data) do + info = %{ + "hide_follows" => hide_follows, + "follower_count" => followers_count, + "following_count" => following_count, + "hide_followers" => hide_followers + } + + info = Map.merge(data.info, info) + Map.put(data, :info, info) + else + {:enabled, false} -> + data + + e -> + Logger.error( + "Follower/Following counter update for #{data.ap_id} failed.\n" <> inspect(e) + ) + + data + end + end + + defp collection_private?(data) do + if is_map(data["first"]) and + data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do + false + else + with {:ok, _data} <- Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do + false + else + {:error, {:ok, %{status: code}}} when code in [401, 403] -> + true + + _e -> + false + end + end + end + def user_data_from_user_object(data) do with {:ok, data} <- MRF.filter(data), {:ok, data} <- object_to_user_data(data) do @@ -1024,7 +1074,8 @@ def user_data_from_user_object(data) do def fetch_and_prepare_user_from_ap_id(ap_id) do with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), - {:ok, data} <- user_data_from_user_object(data) do + {:ok, data} <- user_data_from_user_object(data), + data <- maybe_update_follow_information(data) do {:ok, data} else e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index d14490bb5..e34fe6611 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -1087,10 +1087,6 @@ def upgrade_user_from_ap_id(ap_id) do PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user]) end - if Pleroma.Config.get([:instance, :external_user_synchronization]) do - update_following_followers_counters(user) - end - {:ok, user} else %User{} = user -> {:ok, user} @@ -1123,27 +1119,4 @@ def maybe_fix_user_object(data) do data |> maybe_fix_user_url end - - def update_following_followers_counters(user) do - info = %{} - - following = fetch_counter(user.following_address) - info = if following, do: Map.put(info, :following_count, following), else: info - - followers = fetch_counter(user.follower_address) - info = if followers, do: Map.put(info, :follower_count, followers), else: info - - User.set_info_cache(user, info) - end - - defp fetch_counter(url) do - with {:ok, %{body: body, status: code}} when code in 200..299 <- - Pleroma.HTTP.get( - url, - [{:Accept, "application/activity+json"}] - ), - {:ok, data} <- Jason.decode(body) do - data["totalItems"] - end - end end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index b896a532b..6d05138fb 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -1359,32 +1359,4 @@ test "removes recipient's follower collection from cc", %{user: user} do refute recipient.follower_address in fixed_object["to"] end end - - test "update_following_followers_counters/1" do - user1 = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/masto_closed/followers", - following_address: "http://localhost:4001/users/masto_closed/following" - ) - - user2 = - insert(:user, - local: false, - follower_address: "http://localhost:4001/users/fuser2/followers", - following_address: "http://localhost:4001/users/fuser2/following" - ) - - Transmogrifier.update_following_followers_counters(user1) - Transmogrifier.update_following_followers_counters(user2) - - %{follower_count: followers, following_count: following} = User.get_cached_user_info(user1) - assert followers == 437 - assert following == 152 - - %{follower_count: followers, following_count: following} = User.get_cached_user_info(user2) - - assert followers == 527 - assert following == 267 - end end From e5b850a99115859ceb028c3891f59d5e6ffd5d56 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 13 Jul 2019 23:56:10 +0300 Subject: [PATCH 021/202] Refactor fetching follow information to a separate function --- lib/pleroma/user/info.ex | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 51 +++++++++++++------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 2d8395b73..67e8801ea 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -16,6 +16,7 @@ defmodule Pleroma.User.Info do field(:source_data, :map, default: %{}) field(:note_count, :integer, default: 0) field(:follower_count, :integer, default: 0) + # Should be filled in only for remote users field(:following_count, :integer, default: nil) field(:locked, :boolean, default: false) field(:confirmation_pending, :boolean, default: false) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 0a22fe223..eadd335ca 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1013,17 +1013,15 @@ defp object_to_user_data(data) do {:ok, user_data} end - defp maybe_update_follow_information(data) do - with {:enabled, true} <- - {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, - {:ok, following_data} <- - Fetcher.fetch_and_contain_remote_object_from_id(data.following_address), - following_count <- following_data["totalItems"], - hide_follows <- collection_private?(following_data), + def fetch_follow_information_for_user(user) do + with {:ok, following_data} <- + Fetcher.fetch_and_contain_remote_object_from_id(user.following_address), + following_count when is_integer(following_count) <- following_data["totalItems"], + {:ok, hide_follows} <- collection_private(following_data), {:ok, followers_data} <- - Fetcher.fetch_and_contain_remote_object_from_id(data.follower_address), - followers_count <- followers_data["totalItems"], - hide_followers <- collection_private?(followers_data) do + Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address), + followers_count when is_integer(followers_count) <- followers_data["totalItems"], + {:ok, hide_followers} <- collection_private(followers_data) do info = %{ "hide_follows" => hide_follows, "follower_count" => followers_count, @@ -1031,8 +1029,22 @@ defp maybe_update_follow_information(data) do "hide_followers" => hide_followers } - info = Map.merge(data.info, info) - Map.put(data, :info, info) + info = Map.merge(user.info, info) + {:ok, Map.put(user, :info, info)} + else + {:error, _} = e -> + e + + e -> + {:error, e} + end + end + + defp maybe_update_follow_information(data) do + with {:enabled, true} <- + {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, + {:ok, data} <- fetch_follow_information_for_user(data) do + data else {:enabled, false} -> data @@ -1046,19 +1058,22 @@ defp maybe_update_follow_information(data) do end end - defp collection_private?(data) do + defp collection_private(data) do if is_map(data["first"]) and data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do - false + {:ok, false} else with {:ok, _data} <- Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do - false + {:ok, false} else {:error, {:ok, %{status: code}}} when code in [401, 403] -> - true + {:ok, true} - _e -> - false + {:error, _} = e -> + e + + e -> + {:error, e} end end end From d06d1b751d44802c5c3701f916ae2ce7d3c3be56 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 14 Jul 2019 00:21:35 +0300 Subject: [PATCH 022/202] Use atoms when updating user info --- lib/pleroma/web/activity_pub/activity_pub.ex | 16 ++++++++-------- lib/pleroma/web/activity_pub/transmogrifier.ex | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index eadd335ca..df4155d21 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -986,10 +986,10 @@ defp object_to_user_data(data) do user_data = %{ ap_id: data["id"], info: %{ - "ap_enabled" => true, - "source_data" => data, - "banner" => banner, - "locked" => locked + ap_enabled: true, + source_data: data, + banner: banner, + locked: locked }, avatar: avatar, name: data["name"], @@ -1023,10 +1023,10 @@ def fetch_follow_information_for_user(user) do followers_count when is_integer(followers_count) <- followers_data["totalItems"], {:ok, hide_followers} <- collection_private(followers_data) do info = %{ - "hide_follows" => hide_follows, - "follower_count" => followers_count, - "following_count" => following_count, - "hide_followers" => hide_followers + hide_follows: hide_follows, + follower_count: followers_count, + following_count: following_count, + hide_followers: hide_followers } info = Map.merge(user.info, info) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index e34fe6611..10b362908 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -609,13 +609,13 @@ def handle_incoming( with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) - banner = new_user_data[:info]["banner"] - locked = new_user_data[:info]["locked"] || false + banner = new_user_data[:info][:banner] + locked = new_user_data[:info][:locked] || false update_data = new_user_data |> Map.take([:name, :bio, :avatar]) - |> Map.put(:info, %{"banner" => banner, "locked" => locked}) + |> Map.put(:info, %{banner: banner, locked: locked}) actor |> User.upgrade_changeset(update_data) From 183da33e005c8a8e8472350a3b6b36ff6f82d67d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 14 Jul 2019 00:56:02 +0300 Subject: [PATCH 023/202] Add tests for fetch_follow_information_for_user and check object type when fetching the page --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 +- test/web/activity_pub/activity_pub_test.exs | 81 ++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index df4155d21..c821ba45f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1063,7 +1063,8 @@ defp collection_private(data) do data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do {:ok, false} else - with {:ok, _data} <- Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do + with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <- + Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do {:ok, false} else {:error, {:ok, %{status: code}}} when code in [401, 403] -> diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 59d56f3a7..448ffbf54 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1222,4 +1222,85 @@ test "fetches only public posts for other users" do assert result.id == activity.id end end + + describe "fetch_follow_information_for_user" do + test "syncronizes following/followers counters" do + user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/fuser2/followers", + following_address: "http://localhost:4001/users/fuser2/following" + ) + + {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) + assert user.info.follower_count == 527 + assert user.info.following_count == 267 + end + + test "detects hidden followers" do + mock(fn env -> + case env.url do + "http://localhost:4001/users/masto_closed/followers?page=1" -> + %Tesla.Env{status: 403, body: ""} + + "http://localhost:4001/users/masto_closed/following?page=1" -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + "id" => "http://localhost:4001/users/masto_closed/following?page=1", + "type" => "OrderedCollectionPage" + }) + } + + _ -> + apply(HttpRequestMock, :request, [env]) + end + end) + + user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/masto_closed/followers", + following_address: "http://localhost:4001/users/masto_closed/following" + ) + + {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) + assert user.info.hide_followers == true + assert user.info.hide_follows == false + end + + test "detects hidden follows" do + mock(fn env -> + case env.url do + "http://localhost:4001/users/masto_closed/following?page=1" -> + %Tesla.Env{status: 403, body: ""} + + "http://localhost:4001/users/masto_closed/followers?page=1" -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + "id" => "http://localhost:4001/users/masto_closed/followers?page=1", + "type" => "OrderedCollectionPage" + }) + } + + _ -> + apply(HttpRequestMock, :request, [env]) + end + end) + + user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/masto_closed/followers", + following_address: "http://localhost:4001/users/masto_closed/following" + ) + + {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) + assert user.info.hide_followers == false + assert user.info.hide_follows == true + end + end end From 0c2dcb4c69ed340d02a4b20a4f341f1d9aaaba38 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 14 Jul 2019 01:58:39 +0300 Subject: [PATCH 024/202] Add follow information refetching after following/unfollowing --- lib/pleroma/user.ex | 91 +++++++++++++++----- lib/pleroma/user/info.ex | 10 +++ lib/pleroma/web/activity_pub/activity_pub.ex | 21 +++-- test/web/activity_pub/activity_pub_test.exs | 18 ++-- 4 files changed, 98 insertions(+), 42 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c252e8bff..2e9b01205 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -406,6 +406,8 @@ def follow(%User{} = follower, %User{info: info} = followed) do {1, [follower]} = Repo.update_all(q, []) + follower = maybe_update_following_count(follower) + {:ok, _} = update_follower_count(followed) set_cache(follower) @@ -425,6 +427,8 @@ def unfollow(%User{} = follower, %User{} = followed) do {1, [follower]} = Repo.update_all(q, []) + follower = maybe_update_following_count(follower) + {:ok, followed} = update_follower_count(followed) set_cache(follower) @@ -698,32 +702,75 @@ def update_note_count(%User{} = user) do |> update_and_set_cache() end - def update_follower_count(%User{} = user) do - follower_count_query = - User.Query.build(%{followers: user, deactivated: false}) - |> select([u], %{count: count(u.id)}) + def maybe_fetch_follow_information(user) do + with {:ok, user} <- fetch_follow_information(user) do + user + else + e -> + Logger.error( + "Follower/Following counter update for #{user.ap_id} failed.\n" <> inspect(e) + ) - User - |> where(id: ^user.id) - |> join(:inner, [u], s in subquery(follower_count_query)) - |> update([u, s], - set: [ - info: - fragment( - "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)", - u.info, - s.count - ) - ] - ) - |> select([u], u) - |> Repo.update_all([]) - |> case do - {1, [user]} -> set_cache(user) - _ -> {:error, user} + user end end + def fetch_follow_information(user) do + with {:ok, info} <- ActivityPub.fetch_follow_information_for_user(user) do + info_cng = User.Info.follow_information_update(user.info, info) + + changeset = + user + |> change() + |> put_embed(:info, info_cng) + + update_and_set_cache(changeset) + else + {:error, _} = e -> e + e -> {:error, e} + end + end + + def update_follower_count(%User{} = user) do + unless user.local == false and Pleroma.Config.get([:instance, :external_user_synchronization]) do + follower_count_query = + User.Query.build(%{followers: user, deactivated: false}) + |> select([u], %{count: count(u.id)}) + + User + |> where(id: ^user.id) + |> join(:inner, [u], s in subquery(follower_count_query)) + |> update([u, s], + set: [ + info: + fragment( + "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)", + u.info, + s.count + ) + ] + ) + |> select([u], u) + |> Repo.update_all([]) + |> case do + {1, [user]} -> set_cache(user) + _ -> {:error, user} + end + else + {:ok, maybe_fetch_follow_information(user)} + end + end + + def maybe_update_following_count(%User{local: false} = user) do + if Pleroma.Config.get([:instance, :external_user_synchronization]) do + {:ok, maybe_fetch_follow_information(user)} + else + user + end + end + + def maybe_update_following_count(user), do: user + def remove_duplicated_following(%User{following: following} = user) do uniq_following = Enum.uniq(following) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 67e8801ea..4cc3f2f2c 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -330,4 +330,14 @@ def remove_reblog_mute(info, ap_id) do cast(info, params, [:muted_reblogs]) end + + def follow_information_update(info, params) do + info + |> cast(params, [ + :hide_followers, + :hide_follows, + :follower_count, + :following_count + ]) + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index c821ba45f..2dd9dbf7f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1022,15 +1022,13 @@ def fetch_follow_information_for_user(user) do Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address), followers_count when is_integer(followers_count) <- followers_data["totalItems"], {:ok, hide_followers} <- collection_private(followers_data) do - info = %{ - hide_follows: hide_follows, - follower_count: followers_count, - following_count: following_count, - hide_followers: hide_followers - } - - info = Map.merge(user.info, info) - {:ok, Map.put(user, :info, info)} + {:ok, + %{ + hide_follows: hide_follows, + follower_count: followers_count, + following_count: following_count, + hide_followers: hide_followers + }} else {:error, _} = e -> e @@ -1043,8 +1041,9 @@ def fetch_follow_information_for_user(user) do defp maybe_update_follow_information(data) do with {:enabled, true} <- {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, - {:ok, data} <- fetch_follow_information_for_user(data) do - data + {:ok, info} <- fetch_follow_information_for_user(data) do + info = Map.merge(data.info, info) + Map.put(data, :info, info) else {:enabled, false} -> data diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 448ffbf54..24d8493fe 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1232,9 +1232,9 @@ test "syncronizes following/followers counters" do following_address: "http://localhost:4001/users/fuser2/following" ) - {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) - assert user.info.follower_count == 527 - assert user.info.following_count == 267 + {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) + assert info.follower_count == 527 + assert info.following_count == 267 end test "detects hidden followers" do @@ -1265,9 +1265,9 @@ test "detects hidden followers" do following_address: "http://localhost:4001/users/masto_closed/following" ) - {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) - assert user.info.hide_followers == true - assert user.info.hide_follows == false + {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) + assert info.hide_followers == true + assert info.hide_follows == false end test "detects hidden follows" do @@ -1298,9 +1298,9 @@ test "detects hidden follows" do following_address: "http://localhost:4001/users/masto_closed/following" ) - {:ok, user} = ActivityPub.fetch_follow_information_for_user(user) - assert user.info.hide_followers == false - assert user.info.hide_follows == true + {:ok, info} = ActivityPub.fetch_follow_information_for_user(user) + assert info.hide_followers == false + assert info.hide_follows == true end end end From 168dc97c37f274b258b04eb7e883640b84259714 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 14 Jul 2019 22:04:55 +0300 Subject: [PATCH 025/202] Make opts optional in Pleroma.Notification.for_user_query/2 --- lib/pleroma/notification.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index f680fe049..04bbfa0df 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -33,7 +33,7 @@ def changeset(%Notification{} = notification, attrs) do |> cast(attrs, [:seen]) end - def for_user_query(user, opts) do + def for_user_query(user, opts \\ []) do query = Notification |> where(user_id: ^user.id) From b052a9d4d0323eb64c0a741a499906659a674244 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 14 Jul 2019 22:32:11 +0300 Subject: [PATCH 026/202] Update DigestEmailWorker to compile and send emails via queue --- lib/mix/tasks/pleroma/digest.ex | 2 +- lib/pleroma/digest_email_worker.ex | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/mix/tasks/pleroma/digest.ex b/lib/mix/tasks/pleroma/digest.ex index 19c4ce71e..81c207e10 100644 --- a/lib/mix/tasks/pleroma/digest.ex +++ b/lib/mix/tasks/pleroma/digest.ex @@ -27,7 +27,7 @@ def run(["test", nickname | opts]) do patched_user = %{user | last_digest_emailed_at: last_digest_emailed_at} - :ok = Pleroma.DigestEmailWorker.run([patched_user]) + _user = Pleroma.DigestEmailWorker.perform(patched_user) Mix.shell().info("Digest email have been sent to #{nickname} (#{user.email})") end end diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index 8c28dca18..adc24797f 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -1,6 +1,8 @@ defmodule Pleroma.DigestEmailWorker do import Ecto.Query + @queue_name :digest_emails + def run do config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) @@ -15,18 +17,19 @@ def run do select: u ) |> Pleroma.Repo.all() - |> run() + |> Enum.each(&PleromaJobQueue.enqueue(@queue_name, __MODULE__, [&1])) end - def run([]), do: :ok - - def run([user | users]) do + @doc """ + Send digest email to the given user. + Updates `last_digest_emailed_at` field for the user and returns the updated user. + """ + @spec perform(Pleroma.User.t()) :: Pleroma.User.t() + def perform(user) do with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(user) do Pleroma.Emails.Mailer.deliver_async(email) end Pleroma.User.touch_last_digest_emailed_at(user) - - run(users) end end From e7c175c943e9e3f53df76d812c09cfeffdb1c56b Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Tue, 16 Jul 2019 16:49:50 +0300 Subject: [PATCH 027/202] Use PleromaJobQueue for scheduling --- lib/pleroma/application.ex | 18 ++++++------------ lib/pleroma/digest_email_worker.ex | 2 +- lib/pleroma/quantum_scheduler.ex | 4 ---- mix.exs | 4 ++-- mix.lock | 11 ++--------- 5 files changed, 11 insertions(+), 28 deletions(-) delete mode 100644 lib/pleroma/quantum_scheduler.ex diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 29cd14477..7df6bc9ae 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -115,10 +115,6 @@ def start(_type, _args) do %{ id: Pleroma.ScheduledActivityWorker, start: {Pleroma.ScheduledActivityWorker, :start_link, []} - }, - %{ - id: Pleroma.QuantumScheduler, - start: {Pleroma.QuantumScheduler, :start_link, []} } ] ++ hackney_pool_children() ++ @@ -231,14 +227,12 @@ defp hackney_pool_children do defp after_supervisor_start do with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], - true <- digest_config[:active], - %Crontab.CronExpression{} = schedule <- - Crontab.CronExpression.Parser.parse!(digest_config[:schedule]) do - Pleroma.QuantumScheduler.new_job() - |> Quantum.Job.set_name(:digest_emails) - |> Quantum.Job.set_schedule(schedule) - |> Quantum.Job.set_task(&Pleroma.DigestEmailWorker.run/0) - |> Pleroma.QuantumScheduler.add_job() + true <- digest_config[:active] do + PleromaJobQueue.schedule( + digest_config[:schedule], + :digest_emails, + Pleroma.DigestEmailWorker + ) end :ok diff --git a/lib/pleroma/digest_email_worker.ex b/lib/pleroma/digest_email_worker.ex index adc24797f..18e67d39b 100644 --- a/lib/pleroma/digest_email_worker.ex +++ b/lib/pleroma/digest_email_worker.ex @@ -3,7 +3,7 @@ defmodule Pleroma.DigestEmailWorker do @queue_name :digest_emails - def run do + def perform do config = Pleroma.Config.get([:email_notifications, :digest]) negative_interval = -Map.fetch!(config, :interval) inactivity_threshold = Map.fetch!(config, :inactivity_threshold) diff --git a/lib/pleroma/quantum_scheduler.ex b/lib/pleroma/quantum_scheduler.ex deleted file mode 100644 index 9a3df81f6..000000000 --- a/lib/pleroma/quantum_scheduler.ex +++ /dev/null @@ -1,4 +0,0 @@ -defmodule Pleroma.QuantumScheduler do - use Quantum.Scheduler, - otp_app: :pleroma -end diff --git a/mix.exs b/mix.exs index a4f468726..25332deb9 100644 --- a/mix.exs +++ b/mix.exs @@ -140,7 +140,8 @@ defp deps do {:http_signatures, git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "9789401987096ead65646b52b5a2ca6bf52fc531"}, - {:pleroma_job_queue, "~> 0.2.0"}, + {:pleroma_job_queue, + git: "https://git.pleroma.social/pleroma/pleroma_job_queue.git", ref: "0637ccb1"}, {:telemetry, "~> 0.3"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, @@ -148,7 +149,6 @@ defp deps do {:prometheus_ecto, "~> 1.4"}, {:recon, github: "ferd/recon", tag: "2.4.0"}, {:quack, "~> 0.1.1"}, - {:quantum, "~> 2.3"}, {:joken, "~> 2.0"}, {:benchee, "~> 1.0"}, {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)}, diff --git a/mix.lock b/mix.lock index 4f1214bca..3621d9c27 100644 --- a/mix.lock +++ b/mix.lock @@ -15,7 +15,7 @@ "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"}, "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, - "crontab": {:hex, :crontab, "1.1.5", "2c9439506ceb0e9045de75879e994b88d6f0be88bfe017d58cb356c66c4a5482", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, + "crontab": {:hex, :crontab, "1.1.7", "b9219f0bdc8678b94143655a8f229716c5810c0636a4489f98c0956137e53985", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, "db_connection": {:hex, :db_connection, "2.0.6", "bde2f85d047969c5b5800cb8f4b3ed6316c8cb11487afedac4aa5f93fd39abfa", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"}, @@ -35,8 +35,6 @@ "excoveralls": {:hex, :excoveralls, "0.11.1", "dd677fbdd49114fdbdbf445540ec735808250d56b011077798316505064edb2c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.14.0", "39846a03522456077c6429b4badfd1d55e5e7d0fdfb65e935b7c5e38549d9202", [:rebar3], [], "hexpm"}, - "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"}, - "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, @@ -47,7 +45,6 @@ "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, - "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, @@ -66,26 +63,22 @@ "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, - "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"}, + "pleroma_job_queue": {:git, "https://git.pleroma.social/pleroma/pleroma_job_queue.git", "0637ccb163bab951fc8cd8bcfa3e6c10f0cc0c66", [ref: "0637ccb1"]}, "plug": {:hex, :plug, "1.8.2", "0bcce1daa420f189a6491f3940cc77ea7fb1919761175c9c3b59800d897440fc", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.2", "6055f16868cc4882b24b6e1d63d2bada94fb4978413377a3b32ac16c18dffba2", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.14.3", "5754dee2fdf6e9e508cbf49ab138df964278700b764177e8f3871e658b345a1e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.2.2", "a830e77b79dc6d28183f4db050a7cac926a6c58f1872f9ef94a35cd989aceef8", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.1", "6c768ea9654de871e5b32fab2eac348467b3021604ebebbcbd8bcbe806a65ed5", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.2.1", "964a74dfbc055f781d3a75631e06ce3816a2913976d1df7830283aa3118a797a", [:mix], [{:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, - "prometheus_process_collector": {:hex, :prometheus_process_collector, "1.4.0", "6dbd39e3165b9ef1c94a7a820e9ffe08479f949dcdd431ed4aaea7b250eebfde", [:rebar3], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm"}, - "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, - "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, From ae4fc58589ac48a0853719e6f83b2559b6de44fb Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sat, 20 Jul 2019 01:24:01 +0300 Subject: [PATCH 028/202] Remove flavour from userinfo --- lib/pleroma/user/info.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ae2f66cf1..60b7a82ab 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -43,7 +43,6 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) - field(:flavour, :string, default: nil) field(:email_notifications, :map, default: %{"digest" => false}) field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) From d4ee76ab6355db0bed59b5126fe04d3399561798 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 20 Jul 2019 18:52:41 +0000 Subject: [PATCH 029/202] Apply suggestion to lib/pleroma/user.ex --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 2e9b01205..956ec6240 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -708,7 +708,7 @@ def maybe_fetch_follow_information(user) do else e -> Logger.error( - "Follower/Following counter update for #{user.ap_id} failed.\n" <> inspect(e) + "Follower/Following counter update for #{user.ap_id} failed.\n#{inspect(e)}" ) user From c3ecaea64dd377b586e3b2a5316e90884ec78fe6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 20 Jul 2019 18:53:00 +0000 Subject: [PATCH 030/202] Apply suggestion to lib/pleroma/object/fetcher.ex --- lib/pleroma/object/fetcher.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index bc3e7e5bc..1e60d0082 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -97,7 +97,8 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do end end - def fetch_and_contain_remote_object_from_id(_id) do + def fetch_and_contain_remote_object_from_id(%{"id" => id), do: fetch_and_contain_remote_object_from_id(id) + def fetch_and_contain_remote_object_from_id(_id), do: {:error, "id must be a string"} {:error, "id must be a string"} end end From afc7708dbe00a70be616f00f01b22b0d01b9b61b Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Jul 2019 00:01:58 +0300 Subject: [PATCH 031/202] Fix pleroma_job_queue version --- mix.exs | 3 +-- mix.lock | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 0eb92bb12..315ac808d 100644 --- a/mix.exs +++ b/mix.exs @@ -140,8 +140,7 @@ defp deps do {:http_signatures, git: "https://git.pleroma.social/pleroma/http_signatures.git", ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"}, - {:pleroma_job_queue, - git: "https://git.pleroma.social/pleroma/pleroma_job_queue.git", ref: "0637ccb1"}, + {:pleroma_job_queue, "~> 0.3"}, {:telemetry, "~> 0.3"}, {:prometheus_ex, "~> 3.0"}, {:prometheus_plugs, "~> 1.1"}, diff --git a/mix.lock b/mix.lock index d14dcac21..e7c2f25fc 100644 --- a/mix.lock +++ b/mix.lock @@ -63,7 +63,7 @@ "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, - "pleroma_job_queue": {:git, "https://git.pleroma.social/pleroma/pleroma_job_queue.git", "0637ccb163bab951fc8cd8bcfa3e6c10f0cc0c66", [ref: "0637ccb1"]}, + "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.3.0", "b84538d621f0c3d6fcc1cff9d5648d3faaf873b8b21b94e6503428a07a48ec47", [:mix], [{:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}], "hexpm"}, "plug": {:hex, :plug, "1.8.2", "0bcce1daa420f189a6491f3940cc77ea7fb1919761175c9c3b59800d897440fc", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.2", "6055f16868cc4882b24b6e1d63d2bada94fb4978413377a3b32ac16c18dffba2", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, From e818381042b2bd1d6838f61b150d2816115bddb5 Mon Sep 17 00:00:00 2001 From: kPherox Date: Tue, 23 Jul 2019 18:45:04 +0900 Subject: [PATCH 032/202] Use User.get_or_fetch/1 instead of OStatus.find_or_make_user/1 --- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 9e4da7dca..39bc6147c 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -17,7 +17,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI - alias Pleroma.Web.OStatus alias Pleroma.Web.WebFinger def help_test(conn, _params) do @@ -60,7 +59,7 @@ def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) redirect(conn, to: "/notice/#{activity_id}") else - {err, followee} = OStatus.find_or_make_user(acct) + {err, followee} = User.get_or_fetch(acct) avatar = User.avatar_url(followee) name = followee.nickname id = followee.id From 4af4f6166bd04b5a302856034fdda94dd61045ed Mon Sep 17 00:00:00 2001 From: Sadposter Date: Wed, 24 Jul 2019 11:09:06 +0100 Subject: [PATCH 033/202] honour domain blocks on streaming notifications --- lib/pleroma/web/streamer.ex | 3 +++ test/web/streamer_test.exs | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 86e2dc4dd..d233d2a41 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -234,10 +234,13 @@ defp should_send?(%User{} = user, %Activity{} = item) do blocks = user.info.blocks || [] mutes = user.info.mutes || [] reblog_mutes = user.info.muted_reblogs || [] + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) + %{host: host} = URI.parse(parent.data["actor"]) with parent when not is_nil(parent) <- Object.normalize(item), true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host), true <- thread_containment(item, user) do true else diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index 8f56e7486..95d5e5d58 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -103,6 +103,24 @@ test "it doesn't send notify to the 'user:notification' stream when a thread is Streamer.stream("user:notification", notif) Task.await(task) end + + test "it doesn't send notify to the 'user:notification' stream' when a domain is blocked", %{ + user: user + } do + user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"}) + task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + + Streamer.add_socket( + "user:notification", + %{transport_pid: task.pid, assigns: %{user: user}} + ) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"}) + {:ok, user} = User.block_domain(user, "hecking-lewd-place.com") + {:ok, notif, _} = CommonAPI.favorite(activity.id, user2) + Streamer.stream("user:notification", notif) + Task.await(task) + end end test "it sends to public" do From 48bd3be9cb9b378dfde78e769e2f00ed77129ab9 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Wed, 24 Jul 2019 11:11:33 +0100 Subject: [PATCH 034/202] move domain block check to with block --- lib/pleroma/web/streamer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index d233d2a41..e4259e869 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -235,11 +235,11 @@ defp should_send?(%User{} = user, %Activity{} = item) do mutes = user.info.mutes || [] reblog_mutes = user.info.muted_reblogs || [] domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) - %{host: host} = URI.parse(parent.data["actor"]) with parent when not is_nil(parent) <- Object.normalize(item), true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), + %{host: host} <- URI.parse(parent.data["actor"]), false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host), true <- thread_containment(item, user) do true From f5d574f4ed9aa997a47d03f02adeb701d96f6789 Mon Sep 17 00:00:00 2001 From: sadposter Date: Wed, 24 Jul 2019 11:35:16 +0100 Subject: [PATCH 035/202] check both item and parent domain blocks --- lib/pleroma/web/streamer.ex | 6 ++++-- test/web/streamer_test.exs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index e4259e869..9ee331030 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -239,8 +239,10 @@ defp should_send?(%User{} = user, %Activity{} = item) do with parent when not is_nil(parent) <- Object.normalize(item), true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), - %{host: host} <- URI.parse(parent.data["actor"]), - false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host), + %{host: item_host} <- URI.parse(item.actor), + %{host: parent_host} <- URI.parse(parent.data["actor"]), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), + false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), true <- thread_containment(item, user) do true else diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index 95d5e5d58..d47b37efb 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -115,9 +115,10 @@ test "it doesn't send notify to the 'user:notification' stream' when a domain is %{transport_pid: task.pid, assigns: %{user: user}} ) - {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"}) {:ok, user} = User.block_domain(user, "hecking-lewd-place.com") + {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"}) {:ok, notif, _} = CommonAPI.favorite(activity.id, user2) + Streamer.stream("user:notification", notif) Task.await(task) end From 4504135894d5b52c74818fadc3f7ed49ace1702b Mon Sep 17 00:00:00 2001 From: Eugenij Date: Wed, 24 Jul 2019 15:12:27 +0000 Subject: [PATCH 036/202] Add `domain_blocking` to the relationship API (GET /api/v1/accounts/relationships) --- CHANGELOG.md | 1 + lib/pleroma/user.ex | 25 ++++++++++++------- .../web/mastodon_api/views/account_view.ex | 6 ++--- test/web/mastodon_api/account_view_test.exs | 10 ++++++++ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35a5a6c21..a3f54d19e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add support for categories for custom emojis by reusing the group feature. - Mastodon API: Add support for muting/unmuting notifications - Mastodon API: Add support for the `blocked_by` attribute in the relationship API (`GET /api/v1/accounts/relationships`). +- Mastodon API: Add support for the `domain_blocking` attribute in the relationship API (`GET /api/v1/accounts/relationships`). - Mastodon API: Add `pleroma.deactivated` to the Account entity - Mastodon API: added `/auth/password` endpoint for password reset with rate limit. - Mastodon API: /api/v1/accounts/:id/statuses now supports nicknames or user id diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 982ca8bc1..974f6df18 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -882,19 +882,26 @@ def muted_notifications?(nil, _), do: false def muted_notifications?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.muted_notifications, ap_id) - def blocks?(%User{info: info} = _user, %{ap_id: ap_id}) do - blocks = info.blocks - - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(info.domain_blocks) - - %{host: host} = URI.parse(ap_id) - - Enum.member?(blocks, ap_id) || - Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) + def blocks?(%User{} = user, %User{} = target) do + blocks_ap_id?(user, target) || blocks_domain?(user, target) end def blocks?(nil, _), do: false + def blocks_ap_id?(%User{} = user, %User{} = target) do + Enum.member?(user.info.blocks, target.ap_id) + end + + def blocks_ap_id?(_, _), do: false + + def blocks_domain?(%User{} = user, %User{} = target) do + domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks) + %{host: host} = URI.parse(target.ap_id) + Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) + end + + def blocks_domain?(_, _), do: false + def subscribed_to?(user, %{ap_id: ap_id}) do with %User{} = target <- get_cached_by_ap_id(ap_id) do Enum.member?(target.info.subscribers, user.ap_id) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index befb35c26..b2b06eeb9 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -50,13 +50,13 @@ def render("relationship.json", %{user: %User{} = user, target: %User{} = target id: to_string(target.id), following: User.following?(user, target), followed_by: User.following?(target, user), - blocking: User.blocks?(user, target), - blocked_by: User.blocks?(target, user), + blocking: User.blocks_ap_id?(user, target), + blocked_by: User.blocks_ap_id?(target, user), muting: User.mutes?(user, target), muting_notifications: User.muted_notifications?(user, target), subscribing: User.subscribed_to?(user, target), requested: requested, - domain_blocking: false, + domain_blocking: User.blocks_domain?(user, target), showing_reblogs: User.showing_reblogs?(user, target), endorsed: false } diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index fa44d35cc..905e9af98 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -231,6 +231,16 @@ test "represent a relationship for the blocking and blocked user" do AccountView.render("relationship.json", %{user: user, target: other_user}) end + test "represent a relationship for the user blocking a domain" do + user = insert(:user) + other_user = insert(:user, ap_id: "https://bad.site/users/other_user") + + {:ok, user} = User.block_domain(user, "bad.site") + + assert %{domain_blocking: true, blocking: false} = + AccountView.render("relationship.json", %{user: user, target: other_user}) + end + test "represent a relationship for the user with a pending follow request" do user = insert(:user) other_user = insert(:user, %{info: %User.Info{locked: true}}) From 55341ac71740d3d8aded9c6520e06b9c509a6670 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 24 Jul 2019 15:13:10 +0000 Subject: [PATCH 037/202] tests WebFinger --- lib/pleroma/plugs/set_format_plug.ex | 24 +++++++++++ lib/pleroma/web/web_finger/web_finger.ex | 3 +- .../web/web_finger/web_finger_controller.ex | 43 +++++++++---------- test/plugs/set_format_plug_test.exs | 38 ++++++++++++++++ test/support/http_request_mock.ex | 9 ++++ .../web_finger/web_finger_controller_test.exs | 43 +++++++++++++++++++ test/web/web_finger/web_finger_test.exs | 5 +++ 7 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 lib/pleroma/plugs/set_format_plug.ex create mode 100644 test/plugs/set_format_plug_test.exs diff --git a/lib/pleroma/plugs/set_format_plug.ex b/lib/pleroma/plugs/set_format_plug.ex new file mode 100644 index 000000000..5ca741c64 --- /dev/null +++ b/lib/pleroma/plugs/set_format_plug.ex @@ -0,0 +1,24 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.SetFormatPlug do + import Plug.Conn, only: [assign: 3, fetch_query_params: 1] + + def init(_), do: nil + + def call(conn, _) do + case get_format(conn) do + nil -> conn + format -> assign(conn, :format, format) + end + end + + defp get_format(conn) do + conn.private[:phoenix_format] || + case fetch_query_params(conn) do + %{query_params: %{"_format" => format}} -> format + _ -> nil + end + end +end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index fa34c7ced..0514ade2b 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -187,6 +187,7 @@ def find_lrdd_template(domain) do end end + @spec finger(String.t()) :: {:ok, map()} | {:error, any()} def finger(account) do account = String.trim_leading(account, "@") @@ -220,8 +221,6 @@ def finger(account) do else with {:ok, doc} <- Jason.decode(body) do webfinger_from_json(doc) - else - {:error, e} -> e end end else diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex index b77c75ec5..896eb15f9 100644 --- a/lib/pleroma/web/web_finger/web_finger_controller.ex +++ b/lib/pleroma/web/web_finger/web_finger_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do alias Pleroma.Web.WebFinger + plug(Pleroma.Plugs.SetFormatPlug) plug(Pleroma.Web.FederatingPlug) def host_meta(conn, _params) do @@ -17,30 +18,28 @@ def host_meta(conn, _params) do |> send_resp(200, xml) end - def webfinger(conn, %{"resource" => resource}) do - case get_format(conn) do - n when n in ["xml", "xrd+xml"] -> - with {:ok, response} <- WebFinger.webfinger(resource, "XML") do - conn - |> put_resp_content_type("application/xrd+xml") - |> send_resp(200, response) - else - _e -> send_resp(conn, 404, "Couldn't find user") - end - - n when n in ["json", "jrd+json"] -> - with {:ok, response} <- WebFinger.webfinger(resource, "JSON") do - json(conn, response) - else - _e -> send_resp(conn, 404, "Couldn't find user") - end - - _ -> - send_resp(conn, 404, "Unsupported format") + def webfinger(%{assigns: %{format: format}} = conn, %{"resource" => resource}) + when format in ["xml", "xrd+xml"] do + with {:ok, response} <- WebFinger.webfinger(resource, "XML") do + conn + |> put_resp_content_type("application/xrd+xml") + |> send_resp(200, response) + else + _e -> send_resp(conn, 404, "Couldn't find user") end end - def webfinger(conn, _params) do - send_resp(conn, 400, "Bad Request") + def webfinger(%{assigns: %{format: format}} = conn, %{"resource" => resource}) + when format in ["json", "jrd+json"] do + with {:ok, response} <- WebFinger.webfinger(resource, "JSON") do + json(conn, response) + else + _e -> + conn + |> put_status(404) + |> json("Couldn't find user") + end end + + def webfinger(conn, _params), do: send_resp(conn, 400, "Bad Request") end diff --git a/test/plugs/set_format_plug_test.exs b/test/plugs/set_format_plug_test.exs new file mode 100644 index 000000000..bb21956bb --- /dev/null +++ b/test/plugs/set_format_plug_test.exs @@ -0,0 +1,38 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.SetFormatPlugTest do + use ExUnit.Case, async: true + use Plug.Test + + alias Pleroma.Plugs.SetFormatPlug + + test "set format from params" do + conn = + :get + |> conn("/cofe?_format=json") + |> SetFormatPlug.call([]) + + assert %{format: "json"} == conn.assigns + end + + test "set format from header" do + conn = + :get + |> conn("/cofe") + |> put_private(:phoenix_format, "xml") + |> SetFormatPlug.call([]) + + assert %{format: "xml"} == conn.assigns + end + + test "doesn't set format" do + conn = + :get + |> conn("/cofe") + |> SetFormatPlug.call([]) + + refute conn.assigns[:format] + end +end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 7811f7807..31c085e0d 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -614,6 +614,15 @@ def get( }} end + def get( + "https://social.heldscal.la/.well-known/webfinger?resource=invalid_content@social.heldscal.la", + _, + _, + Accept: "application/xrd+xml,application/jrd+json" + ) do + {:ok, %Tesla.Env{status: 200, body: ""}} + end + def get("http://framatube.org/.well-known/host-meta", _, _, _) do {:ok, %Tesla.Env{ diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs index a14ed3126..7d861cbf5 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -19,6 +19,19 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do :ok end + test "GET host-meta" do + response = + build_conn() + |> get("/.well-known/host-meta") + + assert response.status == 200 + + assert response.resp_body == + ~s() + end + test "Webfinger JRD" do user = insert(:user) @@ -30,6 +43,16 @@ test "Webfinger JRD" do assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost" end + test "it returns 404 when user isn't found (JSON)" do + result = + build_conn() + |> put_req_header("accept", "application/jrd+json") + |> get("/.well-known/webfinger?resource=acct:jimm@localhost") + |> json_response(404) + + assert result == "Couldn't find user" + end + test "Webfinger XML" do user = insert(:user) @@ -41,6 +64,26 @@ test "Webfinger XML" do assert response(response, 200) end + test "it returns 404 when user isn't found (XML)" do + result = + build_conn() + |> put_req_header("accept", "application/xrd+xml") + |> get("/.well-known/webfinger?resource=acct:jimm@localhost") + |> response(404) + + assert result == "Couldn't find user" + end + + test "Sends a 404 when invalid format" do + user = insert(:user) + + assert_raise Phoenix.NotAcceptableError, fn -> + build_conn() + |> put_req_header("accept", "text/html") + |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") + end + end + test "Sends a 400 when resource param is missing" do response = build_conn() diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 0578b4b8e..abf512604 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -40,6 +40,11 @@ test "works for ap_ids" do end describe "fingering" do + test "returns error when fails parse xml or json" do + user = "invalid_content@social.heldscal.la" + assert {:error, %Jason.DecodeError{}} = WebFinger.finger(user) + end + test "returns the info for an OStatus user" do user = "shp@social.heldscal.la" From ac27b94ffa49c15850eab591fc1e0e729ddb4167 Mon Sep 17 00:00:00 2001 From: kPherox Date: Wed, 24 Jul 2019 23:38:38 +0900 Subject: [PATCH 038/202] Change to not require `magic-public-key` on WebFinger --- lib/pleroma/web/web_finger/web_finger.ex | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index fa34c7ced..ad3884c0e 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -86,11 +86,17 @@ def represent_user(user, "XML") do |> XmlBuilder.to_doc() end - defp get_magic_key(magic_key) do - "data:application/magic-public-key," <> magic_key = magic_key + defp get_magic_key("data:application/magic-public-key," <> magic_key) do {:ok, magic_key} - rescue - MatchError -> {:error, "Missing magic key data."} + end + + defp get_magic_key(nil) do + Logger.debug("Undefined magic key.") + {:ok, nil} + end + + defp get_magic_key(_) do + {:error, "Missing magic key data."} end defp webfinger_from_xml(doc) do From 84fca14c3c6b3a5a6f3b0894903867dfa50a78bb Mon Sep 17 00:00:00 2001 From: feld Date: Wed, 24 Jul 2019 15:35:25 +0000 Subject: [PATCH 039/202] Do not prepend /media/ when using base_url This ensures admin has full control over the path where media resides. --- lib/pleroma/upload.ex | 9 ++++++++- test/upload_test.exs | 46 ++++++++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index c47d65241..9f0adde5b 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -228,7 +228,14 @@ defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do "" end - [base_url, "media", path] + prefix = + if is_nil(Pleroma.Config.get([__MODULE__, :base_url])) do + "media" + else + "" + end + + [base_url, prefix, path] |> Path.join() end diff --git a/test/upload_test.exs b/test/upload_test.exs index 32c6977d1..95b16078b 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -122,24 +122,6 @@ test "returns a media url" do assert String.starts_with?(url, Pleroma.Web.base_url() <> "/media/") end - test "returns a media url with configured base_url" do - base_url = "https://cache.pleroma.social" - - File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") - - file = %Plug.Upload{ - content_type: "image/jpg", - path: Path.absname("test/fixtures/image_tmp.jpg"), - filename: "image.jpg" - } - - {:ok, data} = Upload.store(file, base_url: base_url) - - assert %{"url" => [%{"href" => url}]} = data - - assert String.starts_with?(url, base_url <> "/media/") - end - test "copies the file to the configured folder with deduping" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") @@ -266,4 +248,32 @@ test "escapes reserved uri characters" do "%3A%3F%23%5B%5D%40%21%24%26%5C%27%28%29%2A%2B%2C%3B%3D.jpg" end end + + describe "Setting a custom base_url for uploaded media" do + setup do + Pleroma.Config.put([Pleroma.Upload, :base_url], "https://cache.pleroma.social") + + on_exit(fn -> + Pleroma.Config.put([Pleroma.Upload, :base_url], nil) + end) + end + + test "returns a media url with configured base_url" do + base_url = Pleroma.Config.get([Pleroma.Upload, :base_url]) + + File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image_tmp.jpg"), + filename: "image.jpg" + } + + {:ok, data} = Upload.store(file, base_url: base_url) + + assert %{"url" => [%{"href" => url}]} = data + + refute String.starts_with?(url, base_url <> "/media/") + end + end end From 8d9f43e1d1a55f445e4e6e4659b9493cd35d99d9 Mon Sep 17 00:00:00 2001 From: kPherox Date: Thu, 25 Jul 2019 01:27:34 +0900 Subject: [PATCH 040/202] Add WebFinger test for AP-only account --- test/fixtures/tesla_mock/kpherox@mstdn.jp.xml | 10 ++++++++++ test/support/http_request_mock.ex | 8 ++++++++ test/web/web_finger/web_finger_test.exs | 14 ++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 test/fixtures/tesla_mock/kpherox@mstdn.jp.xml diff --git a/test/fixtures/tesla_mock/kpherox@mstdn.jp.xml b/test/fixtures/tesla_mock/kpherox@mstdn.jp.xml new file mode 100644 index 000000000..2ec134eaa --- /dev/null +++ b/test/fixtures/tesla_mock/kpherox@mstdn.jp.xml @@ -0,0 +1,10 @@ + + + acct:kPherox@mstdn.jp + https://mstdn.jp/@kPherox + https://mstdn.jp/users/kPherox + + + + + diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 7811f7807..6684a36e7 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -915,6 +915,14 @@ def get("https://info.pleroma.site/activity3.json", _, _, _) do {:ok, %Tesla.Env{status: 404, body: ""}} end + def get("https://mstdn.jp/.well-known/webfinger?resource=acct:kpherox@mstdn.jp", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml") + }} + end + def get(url, query, body, headers) do {:error, "Not implemented the mock response for get #{inspect(url)}, #{query}, #{inspect(body)}, #{ diff --git a/test/web/web_finger/web_finger_test.exs b/test/web/web_finger/web_finger_test.exs index 0578b4b8e..0d3ef6717 100644 --- a/test/web/web_finger/web_finger_test.exs +++ b/test/web/web_finger/web_finger_test.exs @@ -81,6 +81,20 @@ test "returns the correctly for json ostatus users" do assert data["subscribe_address"] == "https://gnusocial.de/main/ostatussub?profile={uri}" end + test "it work for AP-only user" do + user = "kpherox@mstdn.jp" + + {:ok, data} = WebFinger.finger(user) + + assert data["magic_key"] == nil + assert data["salmon"] == nil + + assert data["topic"] == "https://mstdn.jp/users/kPherox.atom" + assert data["subject"] == "acct:kPherox@mstdn.jp" + assert data["ap_id"] == "https://mstdn.jp/users/kPherox" + assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}" + end + test "it works for friendica" do user = "lain@squeet.me" From b20020da160404f6f668eec2a2a42aaa2b6a09b2 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Wed, 24 Jul 2019 19:28:21 +0000 Subject: [PATCH 041/202] Show the url advertised in the Activity in the Status JSON response --- .../web/mastodon_api/views/status_view.ex | 2 +- .../tesla_mock/wedistribute-article.json | 18 +++++++++++ .../tesla_mock/wedistribute-user.json | 31 +++++++++++++++++++ test/object/fetcher_test.exs | 7 +++++ test/support/http_request_mock.ex | 16 ++++++++++ test/web/mastodon_api/status_view_test.exs | 10 ++++++ 6 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/tesla_mock/wedistribute-article.json create mode 100644 test/fixtures/tesla_mock/wedistribute-user.json diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index de9425959..80df9b2ac 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -222,7 +222,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity if user.local do Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) else - object.data["external_url"] || object.data["id"] + object.data["url"] || object.data["external_url"] || object.data["id"] end %{ diff --git a/test/fixtures/tesla_mock/wedistribute-article.json b/test/fixtures/tesla_mock/wedistribute-article.json new file mode 100644 index 000000000..39dc1b982 --- /dev/null +++ b/test/fixtures/tesla_mock/wedistribute-article.json @@ -0,0 +1,18 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "type": "Article", + "name": "The end is near: Mastodon plans to drop OStatus support", + "content": "\n

The days of OStatus are numbered. The venerable protocol has served as a glue between many different types of servers since the early days of the Fediverse, connecting StatusNet (now GNU Social) to Friendica, Hubzilla, Mastodon, and Pleroma.

\n\n\n\n

Now that many fediverse platforms support ActivityPub as a successor protocol, Mastodon appears to be drawing a line in the sand. In a Patreon update, Eugen Rochko writes:

\n\n\n\n

...OStatus...has overstayed its welcome in the code...and now that most of the network uses ActivityPub, it's time for it to go.

Eugen Rochko, Mastodon creator
\n\n\n\n

The pull request to remove Pubsubhubbub and Salmon, two of the main components of OStatus, has already been merged into Mastodon's master branch.

\n\n\n\n

Some projects will be left in the dark as a side effect of this. GNU Social and PostActiv, for example, both only communicate using OStatus. While some discussion exists regarding adopting ActivityPub for GNU Social, and a plugin is in development, it hasn't been formally adopted yet. We just hope that the Free Software Foundation's instance gets updated in time!

\n", + "summary": "One of the largest platforms in the federated social web is dropping the protocol that it started with.", + "attributedTo": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog", + "url": "https://wedistribute.org/2019/07/mastodon-drops-ostatus/", + "to": [ + "https://www.w3.org/ns/activitystreams#Public", + "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/followers" + ], + "id": "https://wedistribute.org/wp-json/pterotype/v1/object/85810", + "likes": "https://wedistribute.org/wp-json/pterotype/v1/object/85810/likes", + "shares": "https://wedistribute.org/wp-json/pterotype/v1/object/85810/shares" +} diff --git a/test/fixtures/tesla_mock/wedistribute-user.json b/test/fixtures/tesla_mock/wedistribute-user.json new file mode 100644 index 000000000..fe2a15703 --- /dev/null +++ b/test/fixtures/tesla_mock/wedistribute-user.json @@ -0,0 +1,31 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers" + } + ], + "type": "Organization", + "id": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog", + "following": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/following", + "followers": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/followers", + "liked": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/liked", + "inbox": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/inbox", + "outbox": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog/outbox", + "name": "We Distribute", + "preferredUsername": "blog", + "summary": "

Connecting many threads in the federated web. We Distribute is an independent publication dedicated to the fediverse, decentralization, P2P technologies, and Free Software!

", + "url": "https://wedistribute.org/", + "publicKey": { + "id": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog#publicKey", + "owner": "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\r\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1bmUJ+y8PS8JFVi0KugN\r\nFl4pLvLog3V2lsV9ftmCXpveB/WJx66Tr1fQLsU3qYvQFc8UPGWD52zV4RENR1SN\r\nx0O6T2f97KUbRM+Ckow7Jyjtssgl+Mqq8UBZQ/+H8I/1Vpvt5E5hUykhFgwzx9qg\r\nzoIA3OK7alOpQbSoKXo0QcOh6yTRUnMSRMJAgUoZJzzXI/FmH/DtKr7ziQ1T2KWs\r\nVs8mWnTb/OlCxiheLuMlmJNMF+lPyVthvMIxF6Z5gV9d5QAmASSCI628e6uH2EUF\r\nDEEF5jo+Z5ffeNv28953lrnM+VB/wTjl3tYA+zCQeAmUPksX3E+YkXGxj+4rxBAY\r\n8wIDAQAB\r\n-----END PUBLIC KEY-----" + }, + "manuallyApprovesFollowers": false, + "icon": { + "url": "https://wedistribute.org/wp-content/uploads/2019/02/b067de423757a538.png", + "type": "Image", + "mediaType": "image/png" + } +} diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs index 482252cff..0ca87f035 100644 --- a/test/object/fetcher_test.exs +++ b/test/object/fetcher_test.exs @@ -110,6 +110,13 @@ test "it can fetch peertube videos" do assert object end + test "it can fetch wedistribute articles" do + {:ok, object} = + Fetcher.fetch_object_from_id("https://wedistribute.org/wp-json/pterotype/v1/object/85810") + + assert object + end + test "all objects with fake directions are rejected by the object fetcher" do assert {:error, _} = Fetcher.fetch_and_contain_remote_object_from_id( diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 31c085e0d..55cfc1e00 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -301,6 +301,22 @@ def get("https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june- }} end + def get("https://wedistribute.org/wp-json/pterotype/v1/object/85810", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json") + }} + end + + def get("https://wedistribute.org/wp-json/pterotype/v1/actor/-blog", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json") + }} + end + def get("http://mastodon.example.org/users/admin", _, _, Accept: "application/activity+json") do {:ok, %Tesla.Env{ diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs index 3447c5b1f..0b167f839 100644 --- a/test/web/mastodon_api/status_view_test.exs +++ b/test/web/mastodon_api/status_view_test.exs @@ -300,6 +300,16 @@ test "attachments" do assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object}) end + test "put the url advertised in the Activity in to the url attribute" do + id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810" + [activity] = Activity.search(nil, id) + + status = StatusView.render("status.json", %{activity: activity}) + + assert status.uri == id + assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/" + end + test "a reblog" do user = insert(:user) activity = insert(:note_activity) From 03c386614fabe9754ba82a1e89f6cf0ef518f61c Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 25 Jul 2019 03:43:13 +0000 Subject: [PATCH 042/202] fixed test for elixir 1.7.4 --- test/upload/filter/dedupe_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/upload/filter/dedupe_test.exs b/test/upload/filter/dedupe_test.exs index fddd594dc..3de94dc20 100644 --- a/test/upload/filter/dedupe_test.exs +++ b/test/upload/filter/dedupe_test.exs @@ -25,7 +25,7 @@ test "adds shasum" do assert { :ok, - %Pleroma.Upload{id: @shasum, path: "#{@shasum}.jpg"} + %Pleroma.Upload{id: @shasum, path: @shasum <> ".jpg"} } = Dedupe.filter(upload) end end From 7c8abbcb1ccafa79372fd75fdec87db2207b61ec Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 26 Jul 2019 15:33:25 +0200 Subject: [PATCH 043/202] CHANGELOG.md: Add entry for !1484 Related to: https://git.pleroma.social/pleroma/pleroma/merge_requests/1484 [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f54d19e..bd3048b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Changed - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config +- **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired - Configuration: OpenGraph and TwitterCard providers enabled by default - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set From 6b77a88365f3a58cf8d1f9c00ed04532f706b87c Mon Sep 17 00:00:00 2001 From: Maksim Date: Fri, 26 Jul 2019 20:27:38 +0000 Subject: [PATCH 044/202] [#1097] added redirect: /pleroma/admin -> /pleroma/admin/ --- .../web/fallback_redirect_controller.ex | 77 +++++++++++++++++++ lib/pleroma/web/router.ex | 65 ---------------- test/web/fallback_test.exs | 4 + 3 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 lib/pleroma/web/fallback_redirect_controller.ex diff --git a/lib/pleroma/web/fallback_redirect_controller.ex b/lib/pleroma/web/fallback_redirect_controller.ex new file mode 100644 index 000000000..5fbf3695f --- /dev/null +++ b/lib/pleroma/web/fallback_redirect_controller.ex @@ -0,0 +1,77 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Fallback.RedirectController do + use Pleroma.Web, :controller + require Logger + alias Pleroma.User + alias Pleroma.Web.Metadata + + def api_not_implemented(conn, _params) do + conn + |> put_status(404) + |> json(%{error: "Not implemented"}) + end + + def redirector(conn, _params, code \\ 200) + + # redirect to admin section + # /pleroma/admin -> /pleroma/admin/ + # + def redirector(conn, %{"path" => ["pleroma", "admin"]} = _, _code) do + redirect(conn, to: "/pleroma/admin/") + end + + def redirector(conn, _params, code) do + conn + |> put_resp_content_type("text/html") + |> send_file(code, index_file_path()) + end + + def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do + with %User{} = user <- User.get_cached_by_nickname_or_id(maybe_nickname_or_id) do + redirector_with_meta(conn, %{user: user}) + else + nil -> + redirector(conn, params) + end + end + + def redirector_with_meta(conn, params) do + {:ok, index_content} = File.read(index_file_path()) + + tags = + try do + Metadata.build_tags(params) + rescue + e -> + Logger.error( + "Metadata rendering for #{conn.request_path} failed.\n" <> + Exception.format(:error, e, __STACKTRACE__) + ) + + "" + end + + response = String.replace(index_content, "", tags) + + conn + |> put_resp_content_type("text/html") + |> send_resp(200, response) + end + + def index_file_path do + Pleroma.Plugs.InstanceStatic.file_path("index.html") + end + + def registration_page(conn, params) do + redirector(conn, params) + end + + def empty(conn, _params) do + conn + |> put_status(204) + |> text("") + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a9f3826fc..47ee762dc 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -729,68 +729,3 @@ defmodule Pleroma.Web.Router do options("/*path", RedirectController, :empty) end end - -defmodule Fallback.RedirectController do - use Pleroma.Web, :controller - require Logger - alias Pleroma.User - alias Pleroma.Web.Metadata - - def api_not_implemented(conn, _params) do - conn - |> put_status(404) - |> json(%{error: "Not implemented"}) - end - - def redirector(conn, _params, code \\ 200) do - conn - |> put_resp_content_type("text/html") - |> send_file(code, index_file_path()) - end - - def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do - with %User{} = user <- User.get_cached_by_nickname_or_id(maybe_nickname_or_id) do - redirector_with_meta(conn, %{user: user}) - else - nil -> - redirector(conn, params) - end - end - - def redirector_with_meta(conn, params) do - {:ok, index_content} = File.read(index_file_path()) - - tags = - try do - Metadata.build_tags(params) - rescue - e -> - Logger.error( - "Metadata rendering for #{conn.request_path} failed.\n" <> - Exception.format(:error, e, __STACKTRACE__) - ) - - "" - end - - response = String.replace(index_content, "", tags) - - conn - |> put_resp_content_type("text/html") - |> send_resp(200, response) - end - - def index_file_path do - Pleroma.Plugs.InstanceStatic.file_path("index.html") - end - - def registration_page(conn, params) do - redirector(conn, params) - end - - def empty(conn, _params) do - conn - |> put_status(204) - |> text("") - end -end diff --git a/test/web/fallback_test.exs b/test/web/fallback_test.exs index cc78b3ae1..c13db9526 100644 --- a/test/web/fallback_test.exs +++ b/test/web/fallback_test.exs @@ -30,6 +30,10 @@ test "GET /api*path", %{conn: conn} do |> json_response(404) == %{"error" => "Not implemented"} end + test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do + assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/" + end + test "GET /*path", %{conn: conn} do assert conn |> get("/foo") From 961e7785314688b9e2445649c71e12023a982165 Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Sun, 28 Jul 2019 14:17:56 +0200 Subject: [PATCH 045/202] Fix HTTP sig tweak on KeyId --- lib/pleroma/signature.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index 0bf49fd7c..15bf3c317 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -15,7 +15,7 @@ def key_id_to_actor_id(key_id) do |> Map.put(:fragment, nil) uri = - if String.ends_with?(uri.path, "/publickey") do + if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do Map.put(uri, :path, String.replace(uri.path, "/publickey", "")) else uri From 02dc651828af00ba88a687570833333d4b939c7e Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Sun, 28 Jul 2019 20:24:39 +0000 Subject: [PATCH 046/202] Handle 303 redirects --- lib/pleroma/http/connection.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index a1460d303..7e2c6f5e8 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.Connection do connect_timeout: 10_000, recv_timeout: 20_000, follow_redirect: true, + force_redirect: true, pool: :federation ] @adapter Application.get_env(:tesla, :adapter) From 6a4b8b2681023dc355331999aeac6c24c5a21f7f Mon Sep 17 00:00:00 2001 From: Maksim Date: Sun, 28 Jul 2019 20:29:26 +0000 Subject: [PATCH 047/202] fixed User.update_and_set_cache for stale user --- lib/pleroma/user.ex | 2 +- test/user_test.exs | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 974f6df18..6e2fd3af8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -471,7 +471,7 @@ def set_cache(%User{} = user) do end def update_and_set_cache(changeset) do - with {:ok, user} <- Repo.update(changeset) do + with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do set_cache(user) else e -> e diff --git a/test/user_test.exs b/test/user_test.exs index 8a7b7537f..556df45fd 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1369,4 +1369,28 @@ test "user with internal-prefixed nickname returns true" do assert User.is_internal_user?(user) end end + + describe "update_and_set_cache/1" do + test "returns error when user is stale instead Ecto.StaleEntryError" do + user = insert(:user) + + changeset = Ecto.Changeset.change(user, bio: "test") + + Repo.delete(user) + + assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} = + User.update_and_set_cache(changeset) + end + + test "performs update cache if user updated" do + user = insert(:user) + assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") + + changeset = Ecto.Changeset.change(user, bio: "test-bio") + + assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset) + assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") + assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id) + end + end end From 242f5c585ed797917ba8c61ceb5d266f4c670c90 Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Sun, 28 Jul 2019 20:30:10 +0000 Subject: [PATCH 048/202] add account confirmation email resend in mastodon api --- CHANGELOG.md | 1 + config/config.exs | 3 +- docs/api/pleroma_api.md | 8 ++++ .../mastodon_api/mastodon_api_controller.ex | 14 +++++++ lib/pleroma/web/router.ex | 6 +++ .../mastodon_api_controller_test.exs | 41 +++++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd3048b19..20f4eea41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ActivityPub: Add an internal service actor for fetching ActivityPub objects. - ActivityPub: Optional signing of ActivityPub object fetches. - Admin API: Endpoint for fetching latest user's statuses +- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=` for resending account confirmation. ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/config/config.exs b/config/config.exs index 569411866..17770640a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -534,7 +534,8 @@ relation_id_action: {60_000, 2}, statuses_actions: {10_000, 15}, status_id_action: {60_000, 3}, - password_reset: {1_800_000, 5} + password_reset: {1_800_000, 5}, + account_confirmation_resend: {8_640_000, 5} # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index d83ebd734..5698e88ac 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -245,6 +245,14 @@ See [Admin-API](Admin-API.md) - PATCH `/api/v1/pleroma/accounts/update_banner`: Set/clear user banner image - PATCH `/api/v1/pleroma/accounts/update_background`: Set/clear user background image +## `/api/v1/pleroma/accounts/confirmation_resend` +### Resend confirmation email +* Method `POST` +* Params: + * `email`: email of that needs to be verified +* Authentication: not required +* Response: 204 No Content + ## `/api/v1/pleroma/mascot` ### Gets user mascot image * Method `GET` diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index d660f3f05..5bdbb709b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -4,6 +4,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [json_response: 3] + alias Ecto.Changeset alias Pleroma.Activity alias Pleroma.Bookmark @@ -74,6 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do plug(RateLimiter, :app_account_creation when action == :account_register) plug(RateLimiter, :search when action in [:search, :search2, :account_search]) plug(RateLimiter, :password_reset when action == :password_reset) + plug(RateLimiter, :account_confirmation_resend when action == :account_confirmation_resend) @local_mastodon_name "Mastodon-Local" @@ -1839,6 +1843,16 @@ def password_reset(conn, params) do end end + def account_confirmation_resend(conn, params) do + nickname_or_email = params["email"] || params["nickname"] + + with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email), + {:ok, _} <- User.try_send_confirmation_email(user) do + conn + |> json_response(:no_content, "") + end + end + def try_render(conn, target, params) when is_binary(target) do case render(conn, target, params) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 47ee762dc..4e1ab6c33 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -412,6 +412,12 @@ defmodule Pleroma.Web.Router do get("/accounts/search", SearchController, :account_search) + post( + "/pleroma/accounts/confirmation_resend", + MastodonAPIController, + :account_confirmation_resend + ) + scope [] do pipe_through(:oauth_read_or_public) diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index ce2e44499..d7f92fac2 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3923,4 +3923,45 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} do assert conn.resp_body == "" end end + + describe "POST /api/v1/pleroma/accounts/confirmation_resend" do + setup do + setting = Pleroma.Config.get([:instance, :account_activation_required]) + + unless setting do + Pleroma.Config.put([:instance, :account_activation_required], true) + on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) + end + + user = insert(:user) + info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true) + + {:ok, user} = + user + |> Changeset.change() + |> Changeset.put_embed(:info, info_change) + |> Repo.update() + + assert user.info.confirmation_pending + + [user: user] + end + + test "resend account confirmation email", %{conn: conn, user: user} do + conn + |> assign(:user, user) + |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") + |> json_response(:no_content) + + email = Pleroma.Emails.UserEmail.account_confirmation_email(user) + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body + ) + end + end end From 492d854e7aa29a2438dbbe2f95e509e43328eb7f Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sun, 28 Jul 2019 21:29:10 +0000 Subject: [PATCH 049/202] transmogrifier: use User.delete() instead of handrolled user deletion code for remote users Closes #1104 --- CHANGELOG.md | 1 + .../web/activity_pub/transmogrifier.ex | 15 +---- test/notification_test.exs | 58 +++++++++++++++++++ 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f4eea41..48379b757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Rich Media: Parser failing when no TTL can be found by image TTL setters - Rich Media: The crawled URL is now spliced into the rich media data. - ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification. +- ActivityPub S2S: remote user deletions now work the same as local user deletions. ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 602ae48e1..7f06e6edd 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -656,20 +656,7 @@ def handle_incoming( nil -> case User.get_cached_by_ap_id(object_id) do %User{ap_id: ^actor} = user -> - {:ok, followers} = User.get_followers(user) - - Enum.each(followers, fn follower -> - User.unfollow(follower, user) - end) - - {:ok, friends} = User.get_friends(user) - - Enum.each(friends, fn followed -> - User.unfollow(user, followed) - end) - - User.invalidate_cache(user) - Repo.delete(user) + User.delete(user) nil -> :error diff --git a/test/notification_test.exs b/test/notification_test.exs index 28f8df49d..c88ac54bd 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -564,6 +564,64 @@ test "replying to a deleted post without tagging does not generate a notificatio assert Enum.empty?(Notification.for_user(user)) end + + test "notifications are deleted if a local user is deleted" do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = + CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}", "visibility" => "direct"}) + + refute Enum.empty?(Notification.for_user(other_user)) + + User.delete(user) + + assert Enum.empty?(Notification.for_user(other_user)) + end + + test "notifications are deleted if a remote user is deleted" do + remote_user = insert(:user) + local_user = insert(:user) + + dm_message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "type" => "Create", + "actor" => remote_user.ap_id, + "id" => remote_user.ap_id <> "/activities/test", + "to" => [local_user.ap_id], + "cc" => [], + "object" => %{ + "type" => "Note", + "content" => "Hello!", + "tag" => [ + %{ + "type" => "Mention", + "href" => local_user.ap_id, + "name" => "@#{local_user.nickname}" + } + ], + "to" => [local_user.ap_id], + "cc" => [], + "attributedTo" => remote_user.ap_id + } + } + + {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message) + + refute Enum.empty?(Notification.for_user(local_user)) + + delete_user_message = %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => remote_user.ap_id <> "/activities/delete", + "actor" => remote_user.ap_id, + "type" => "Delete", + "object" => remote_user.ap_id + } + + {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message) + + assert Enum.empty?(Notification.for_user(local_user)) + end end describe "for_user" do From 9d78b3b281ff7f758d4e0dce19fd74d938e47ccc Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 29 Jul 2019 02:12:35 +0000 Subject: [PATCH 050/202] mix: add ex_const dependency --- mix.exs | 1 + mix.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/mix.exs b/mix.exs index e69940c5d..2a8fe2e9d 100644 --- a/mix.exs +++ b/mix.exs @@ -150,6 +150,7 @@ defp deps do {:benchee, "~> 1.0"}, {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)}, {:ex_rated, "~> 1.3"}, + {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, {:excoveralls, "~> 0.11.1", only: :test}, {:mox, "~> 0.5", only: :test} diff --git a/mix.lock b/mix.lock index 5f20878d3..65da7be8b 100644 --- a/mix.lock +++ b/mix.lock @@ -27,6 +27,7 @@ "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, + "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"}, From b93498eb5289dc92587b77c316ed9f697bb9e5c8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 29 Jul 2019 02:43:19 +0000 Subject: [PATCH 051/202] constants: add as_public constant and use it everywhere --- lib/mix/tasks/pleroma/database.ex | 12 ++++++--- lib/pleroma/activity/search.ex | 4 ++- lib/pleroma/constants.ex | 9 +++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 27 +++++++------------ .../web/activity_pub/mrf/hellthread_policy.ex | 11 +++++--- .../web/activity_pub/mrf/keyword_policy.ex | 8 +++--- .../web/activity_pub/mrf/reject_non_public.ex | 6 ++--- .../web/activity_pub/mrf/simple_policy.ex | 12 ++++----- .../web/activity_pub/mrf/tag_policy.ex | 15 ++++++----- lib/pleroma/web/activity_pub/publisher.ex | 6 ++--- .../web/activity_pub/transmogrifier.ex | 11 ++++---- lib/pleroma/web/activity_pub/utils.ex | 13 ++++----- lib/pleroma/web/activity_pub/visibility.ex | 8 +++--- lib/pleroma/web/auth/authenticator.ex | 3 +-- lib/pleroma/web/common_api/common_api.ex | 3 +-- lib/pleroma/web/common_api/utils.ex | 5 ++-- .../mastodon_api/mastodon_api_controller.ex | 6 ++--- lib/pleroma/web/oauth/oauth_controller.ex | 3 +-- lib/pleroma/web/oauth/token.ex | 3 +-- .../web/ostatus/activity_representer.ex | 3 ++- .../web/ostatus/handlers/note_handler.ex | 5 ++-- .../rich_media/parsers/ttl/aws_signed_url.ex | 3 +-- lib/pleroma/web/twitter_api/twitter_api.ex | 4 ++- .../web/twitter_api/views/activity_view.ex | 3 ++- .../twitter_api/views/notification_view.ex | 4 ++- test/web/push/impl_test.exs | 6 ++--- 26 files changed, 104 insertions(+), 89 deletions(-) create mode 100644 lib/pleroma/constants.ex diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index e91fb31d1..8547a329a 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -8,6 +8,7 @@ defmodule Mix.Tasks.Pleroma.Database do alias Pleroma.Repo alias Pleroma.User require Logger + require Pleroma.Constants import Mix.Pleroma use Mix.Task @@ -99,10 +100,15 @@ def run(["prune_objects" | args]) do NaiveDateTime.utc_now() |> NaiveDateTime.add(-(deadline * 86_400)) - public = "https://www.w3.org/ns/activitystreams#Public" - from(o in Object, - where: fragment("?->'to' \\? ? OR ?->'cc' \\? ?", o.data, ^public, o.data, ^public), + where: + fragment( + "?->'to' \\? ? OR ?->'cc' \\? ?", + o.data, + ^Pleroma.Constants.as_public(), + o.data, + ^Pleroma.Constants.as_public() + ), where: o.inserted_at < ^time_deadline, where: fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host()) diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index 0cc3770a7..f847ac238 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -9,6 +9,8 @@ defmodule Pleroma.Activity.Search do alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility + require Pleroma.Constants + import Ecto.Query def search(user, search_query, options \\ []) do @@ -39,7 +41,7 @@ def maybe_restrict_author(query, _), do: query defp restrict_public(q) do from([a, o] in q, where: fragment("?->>'type' = 'Create'", a.data), - where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients + where: ^Pleroma.Constants.as_public() in a.recipients ) end diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex new file mode 100644 index 000000000..ef1418543 --- /dev/null +++ b/lib/pleroma/constants.ex @@ -0,0 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Constants do + use Const + + const(as_public, do: "https://www.w3.org/ns/activitystreams#Public") +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a42c50875..6fd7fef92 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do import Pleroma.Web.ActivityPub.Visibility require Logger + require Pleroma.Constants # For Announce activities, we filter the recipients based on following status for any actors # that match actual users. See issue #164 for more information about why this is necessary. @@ -207,8 +208,6 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do def stream_out_participations(_, _), do: :noop def stream_out(activity) do - public = "https://www.w3.org/ns/activitystreams#Public" - if activity.data["type"] in ["Create", "Announce", "Delete"] do object = Object.normalize(activity) # Do not stream out poll replies @@ -216,7 +215,7 @@ def stream_out(activity) do Pleroma.Web.Streamer.stream("user", activity) Pleroma.Web.Streamer.stream("list", activity) - if Enum.member?(activity.data["to"], public) do + if get_visibility(activity) == "public" do Pleroma.Web.Streamer.stream("public", activity) if activity.local do @@ -238,13 +237,8 @@ def stream_out(activity) do end end else - # TODO: Write test, replace with visibility test - if !Enum.member?(activity.data["cc"] || [], public) && - !Enum.member?( - activity.data["to"], - User.get_cached_by_ap_id(activity.data["actor"]).follower_address - ), - do: Pleroma.Web.Streamer.stream("direct", activity) + if get_visibility(activity) == "direct", + do: Pleroma.Web.Streamer.stream("direct", activity) end end end @@ -514,7 +508,7 @@ def flag( end defp fetch_activities_for_context_query(context, opts) do - public = ["https://www.w3.org/ns/activitystreams#Public"] + public = [Pleroma.Constants.as_public()] recipients = if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public @@ -555,7 +549,7 @@ def fetch_latest_activity_id_for_context(context, opts \\ %{}) do end def fetch_public_activities(opts \\ %{}) do - q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts) + q = fetch_activities_query([Pleroma.Constants.as_public()], opts) q |> restrict_unlisted() @@ -646,10 +640,9 @@ defp user_activities_recipients(%{"godmode" => true}) do defp user_activities_recipients(%{"reading_user" => reading_user}) do if reading_user do - ["https://www.w3.org/ns/activitystreams#Public"] ++ - [reading_user.ap_id | reading_user.following] + [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | reading_user.following] else - ["https://www.w3.org/ns/activitystreams#Public"] + [Pleroma.Constants.as_public()] end end @@ -834,7 +827,7 @@ defp restrict_unlisted(query) do fragment( "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)", activity.data, - ^["https://www.w3.org/ns/activitystreams#Public"] + ^[Pleroma.Constants.as_public()] ) ) end @@ -971,7 +964,7 @@ def fetch_activities_bounded_query(query, recipients, recipients_with_public) do where: fragment("? && ?", activity.recipients, ^recipients) or (fragment("? && ?", activity.recipients, ^recipients_with_public) and - "https://www.w3.org/ns/activitystreams#Public" in activity.recipients) + ^Pleroma.Constants.as_public() in activity.recipients) ) end diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index a699f6a7e..377987cf2 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -4,6 +4,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do alias Pleroma.User + + require Pleroma.Constants + @moduledoc "Block messages with too much mentions (configurable)" @behaviour Pleroma.Web.ActivityPub.MRF @@ -19,12 +22,12 @@ defp delist_message(message, threshold) when threshold > 0 do when follower_collection? and recipients > threshold -> message |> Map.put("to", [follower_collection]) - |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", [Pleroma.Constants.as_public()]) {:public, recipients} when recipients > threshold -> message |> Map.put("to", []) - |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", [Pleroma.Constants.as_public()]) _ -> message @@ -51,10 +54,10 @@ defp get_recipient_count(message) do recipients = (message["to"] || []) ++ (message["cc"] || []) follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address - if Enum.member?(recipients, "https://www.w3.org/ns/activitystreams#Public") do + if Enum.member?(recipients, Pleroma.Constants.as_public()) do recipients = recipients - |> List.delete("https://www.w3.org/ns/activitystreams#Public") + |> List.delete(Pleroma.Constants.as_public()) |> List.delete(follower_collection) {:public, length(recipients)} diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex index d5c341433..4eec8b916 100644 --- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do + require Pleroma.Constants + @moduledoc "Reject or Word-Replace messages with a keyword or regex" @behaviour Pleroma.Web.ActivityPub.MRF @@ -31,12 +33,12 @@ defp check_reject(%{"object" => %{"content" => content, "summary" => summary}} = defp check_ftl_removal( %{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message ) do - if "https://www.w3.org/ns/activitystreams#Public" in to and + if Pleroma.Constants.as_public() in to and Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern -> string_matches?(content, pattern) or string_matches?(summary, pattern) end) do - to = List.delete(to, "https://www.w3.org/ns/activitystreams#Public") - cc = ["https://www.w3.org/ns/activitystreams#Public" | message["cc"] || []] + to = List.delete(to, Pleroma.Constants.as_public()) + cc = [Pleroma.Constants.as_public() | message["cc"] || []] message = message diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index da13fd7c7..457b6ee10 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do @behaviour Pleroma.Web.ActivityPub.MRF - @public "https://www.w3.org/ns/activitystreams#Public" + require Pleroma.Constants @impl true def filter(%{"type" => "Create"} = object) do @@ -19,8 +19,8 @@ def filter(%{"type" => "Create"} = object) do # Determine visibility visibility = cond do - @public in object["to"] -> "public" - @public in object["cc"] -> "unlisted" + Pleroma.Constants.as_public() in object["to"] -> "public" + Pleroma.Constants.as_public() in object["cc"] -> "unlisted" user.follower_address in object["to"] -> "followers" true -> "direct" end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 2cf63d3db..f266457e3 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do @moduledoc "Filter activities depending on their origin instance" @behaviour MRF + require Pleroma.Constants + defp check_accept(%{host: actor_host} = _actor_info, object) do accepts = Pleroma.Config.get([:mrf_simple, :accept]) @@ -89,14 +91,10 @@ defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do object = with true <- MRF.subdomain_match?(timeline_removal, actor_host), user <- User.get_cached_by_ap_id(object["actor"]), - true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do - to = - List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++ - [user.follower_address] + true <- Pleroma.Constants.as_public() in object["to"] do + to = List.delete(object["to"], Pleroma.Constants.as_public()) ++ [user.follower_address] - cc = - List.delete(object["cc"], user.follower_address) ++ - ["https://www.w3.org/ns/activitystreams#Public"] + cc = List.delete(object["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()] object |> Map.put("to", to) diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index b42c4ed76..70edf4f7f 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do - `mrf_tag:disable-any-subscription`: Reject any follow requests """ - @public "https://www.w3.org/ns/activitystreams#Public" + require Pleroma.Constants defp get_tags(%User{tags: tags}) when is_list(tags), do: tags defp get_tags(_), do: [] @@ -70,9 +70,9 @@ defp process_tag( ) do user = User.get_cached_by_ap_id(actor) - if Enum.member?(to, @public) do - to = List.delete(to, @public) ++ [user.follower_address] - cc = List.delete(cc, user.follower_address) ++ [@public] + if Enum.member?(to, Pleroma.Constants.as_public()) do + to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address] + cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()] object = object @@ -103,9 +103,10 @@ defp process_tag( ) do user = User.get_cached_by_ap_id(actor) - if Enum.member?(to, @public) or Enum.member?(cc, @public) do - to = List.delete(to, @public) ++ [user.follower_address] - cc = List.delete(cc, @public) + if Enum.member?(to, Pleroma.Constants.as_public()) or + Enum.member?(cc, Pleroma.Constants.as_public()) do + to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address] + cc = List.delete(cc, Pleroma.Constants.as_public()) object = object diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 016d78216..46edab0bd 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier + require Pleroma.Constants + import Pleroma.Web.ActivityPub.Visibility @behaviour Pleroma.Web.Federator.Publisher @@ -117,8 +119,6 @@ defp get_cc_ap_ids(ap_id, recipients) do |> Enum.map(& &1.ap_id) end - @as_public "https://www.w3.org/ns/activitystreams#Public" - defp maybe_use_sharedinbox(%User{info: %{source_data: data}}), do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"] @@ -145,7 +145,7 @@ def determine_inbox( type == "Delete" -> maybe_use_sharedinbox(user) - @as_public in to || @as_public in cc -> + Pleroma.Constants.as_public() in to || Pleroma.Constants.as_public() in cc -> maybe_use_sharedinbox(user) length(to) + length(cc) > 1 -> diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 7f06e6edd..44bb1cb9a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do import Ecto.Query require Logger + require Pleroma.Constants @doc """ Modifies an incoming AP object (mastodon format) to our internal format. @@ -102,8 +103,7 @@ def fix_explicit_addressing(object) do follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address - explicit_mentions = - explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public", follower_collection] + explicit_mentions = explicit_mentions ++ [Pleroma.Constants.as_public(), follower_collection] fix_explicit_addressing(object, explicit_mentions, follower_collection) end @@ -115,11 +115,11 @@ def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collec if followers_collection not in recipients do cond do - "https://www.w3.org/ns/activitystreams#Public" in cc -> + Pleroma.Constants.as_public() in cc -> to = to ++ [followers_collection] Map.put(object, "to", to) - "https://www.w3.org/ns/activitystreams#Public" in to -> + Pleroma.Constants.as_public() in to -> cc = cc ++ [followers_collection] Map.put(object, "cc", cc) @@ -480,8 +480,7 @@ def handle_incoming( {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower), {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]), - {_, false} <- - {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked}, + {_, false} <- {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked}, {_, false} <- {:user_locked, User.locked?(followed)}, {_, {:ok, follower}} <- {:follow, User.follow(follower, followed)}, {_, {:ok, _}} <- diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index c146f59d4..39074888b 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -18,6 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do import Ecto.Query require Logger + require Pleroma.Constants @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"] @supported_report_states ~w(open closed resolved) @@ -418,7 +419,7 @@ def make_follow_data( "type" => "Follow", "actor" => follower_id, "to" => [followed_id], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [Pleroma.Constants.as_public()], "object" => followed_id, "state" => "pending" } @@ -510,7 +511,7 @@ def make_announce_data( "actor" => ap_id, "object" => id, "to" => [user.follower_address, object.data["actor"]], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [Pleroma.Constants.as_public()], "context" => object.data["context"] } @@ -530,7 +531,7 @@ def make_unannounce_data( "actor" => ap_id, "object" => activity.data, "to" => [user.follower_address, activity.data["actor"]], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [Pleroma.Constants.as_public()], "context" => context } @@ -547,7 +548,7 @@ def make_unlike_data( "actor" => ap_id, "object" => activity.data, "to" => [user.follower_address, activity.data["actor"]], - "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => [Pleroma.Constants.as_public()], "context" => context } @@ -556,7 +557,7 @@ def make_unlike_data( def add_announce_to_object( %Activity{ - data: %{"actor" => actor, "cc" => ["https://www.w3.org/ns/activitystreams#Public"]} + data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]} }, object ) do @@ -765,7 +766,7 @@ defp get_updated_targets( ) do cc = Map.get(data, "cc", []) follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address - public = "https://www.w3.org/ns/activitystreams#Public" + public = Pleroma.Constants.as_public() case visibility do "public" -> diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 097fceb08..dfb166b65 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -8,14 +8,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do alias Pleroma.Repo alias Pleroma.User - @public "https://www.w3.org/ns/activitystreams#Public" + require Pleroma.Constants @spec is_public?(Object.t() | Activity.t() | map()) :: boolean() def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def is_public?(%Object{data: data}), do: is_public?(data) def is_public?(%Activity{data: data}), do: is_public?(data) def is_public?(%{"directMessage" => true}), do: false - def is_public?(data), do: @public in (data["to"] ++ (data["cc"] || [])) + def is_public?(data), do: Pleroma.Constants.as_public() in (data["to"] ++ (data["cc"] || [])) def is_private?(activity) do with false <- is_public?(activity), @@ -73,10 +73,10 @@ def get_visibility(object) do cc = object.data["cc"] || [] cond do - @public in to -> + Pleroma.Constants.as_public() in to -> "public" - @public in cc -> + Pleroma.Constants.as_public() in cc -> "unlisted" # this should use the sql for the object's activity diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index d4e0ffa80..dd49987f7 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -21,8 +21,7 @@ def get_user(plug), do: implementation().get_user(plug) def create_from_registration(plug, registration), do: implementation().create_from_registration(plug, registration) - @callback get_registration(Plug.Conn.t()) :: - {:ok, Registration.t()} | {:error, any()} + @callback get_registration(Plug.Conn.t()) :: {:ok, Registration.t()} | {:error, any()} def get_registration(plug), do: implementation().get_registration(plug) @callback handle_error(Plug.Conn.t(), any()) :: any() diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 44af6a773..2db58324b 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -300,8 +300,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do } } = activity <- get_by_id_or_ap_id(id_or_ap_id), true <- Visibility.is_public?(activity), - %{valid?: true} = info_changeset <- - User.Info.add_pinnned_activity(user.info, activity), + %{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity), changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), {:ok, _user} <- User.update_and_set_cache(changeset) do diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 94462c3dd..d80fffa26 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do alias Pleroma.Web.MediaProxy require Logger + require Pleroma.Constants # This is a hack for twidere. def get_by_id_or_ap_id(id) do @@ -66,7 +67,7 @@ def attachments_from_ids_descs(ids, descs_str) do @spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) :: {list(String.t()), list(String.t())} def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do - to = ["https://www.w3.org/ns/activitystreams#Public" | mentioned_users] + to = [Pleroma.Constants.as_public() | mentioned_users] cc = [user.follower_address] if inReplyTo do @@ -78,7 +79,7 @@ def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do to = [user.follower_address | mentioned_users] - cc = ["https://www.w3.org/ns/activitystreams#Public"] + cc = [Pleroma.Constants.as_public()] if inReplyTo do {Enum.uniq([inReplyTo.data["actor"] | to]), cc} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 5bdbb709b..174e93468 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -49,6 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do import Ecto.Query require Logger + require Pleroma.Constants @rate_limited_relations_actions ~w(follow unfollow)a @@ -1224,10 +1225,9 @@ def user_favourites(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params recipients = if for_user do - ["https://www.w3.org/ns/activitystreams#Public"] ++ - [for_user.ap_id | for_user.following] + [Pleroma.Constants.as_public()] ++ [for_user.ap_id | for_user.following] else - ["https://www.w3.org/ns/activitystreams#Public"] + [Pleroma.Constants.as_public()] end activities = diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index ef53b7ae3..81eae2c8b 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -365,8 +365,7 @@ def registration_details(%Plug.Conn{} = conn, %{"authorization" => auth_attrs}) def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "connect"} = params) do with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), %Registration{} = registration <- Repo.get(Registration, registration_id), - {_, {:ok, auth}} <- - {:create_authorization, do_create_authorization(conn, params)}, + {_, {:ok, auth}} <- {:create_authorization, do_create_authorization(conn, params)}, %User{} = user <- Repo.preload(auth, :user).user, {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do conn diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 90c304487..40f131b57 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -44,8 +44,7 @@ def get_by_refresh_token(%App{id: app_id} = _app, token) do |> Repo.find_resource() end - @spec exchange_token(App.t(), Authorization.t()) :: - {:ok, Token.t()} | {:error, Changeset.t()} + @spec exchange_token(App.t(), Authorization.t()) :: {:ok, Token.t()} | {:error, Changeset.t()} def exchange_token(app, auth) do with {:ok, auth} <- Authorization.use_token(auth), true <- auth.app_id == app.id do diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 95037125d..760345301 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do alias Pleroma.Web.OStatus.UserRepresenter require Logger + require Pleroma.Constants defp get_href(id) do with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do @@ -34,7 +35,7 @@ defp get_mentions(to) do Enum.map(to, fn id -> cond do # Special handling for the AP/Ostatus public collections - "https://www.w3.org/ns/activitystreams#Public" == id -> + Pleroma.Constants.as_public() == id -> {:link, [ rel: "mentioned", diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex index 8e0adad91..3005e8f57 100644 --- a/lib/pleroma/web/ostatus/handlers/note_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do require Logger + require Pleroma.Constants alias Pleroma.Activity alias Pleroma.Object @@ -49,7 +50,7 @@ def get_people_mentions(entry) do def get_collection_mentions(entry) do transmogrify = fn "http://activityschema.org/collection/public" -> - "https://www.w3.org/ns/activitystreams#Public" + Pleroma.Constants.as_public() group -> group @@ -126,7 +127,7 @@ def handle_note(entry, doc \\ nil, options \\ []) do to <- make_to_list(actor, mentions), date <- XML.string_from_xpath("//published", entry), unlisted <- XML.string_from_xpath("//mastodon:scope", entry) == "unlisted", - cc <- if(unlisted, do: ["https://www.w3.org/ns/activitystreams#Public"], else: []), + cc <- if(unlisted, do: [Pleroma.Constants.as_public()], else: []), note <- CommonAPI.Utils.make_note_data( actor.ap_id, diff --git a/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex b/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex index 014c0935f..0dc1efdaf 100644 --- a/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex +++ b/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex @@ -19,8 +19,7 @@ defp is_aws_signed_url(nil), do: nil defp is_aws_signed_url(image) when is_binary(image) do %URI{host: host, query: query} = URI.parse(image) - if String.contains?(host, "amazonaws.com") and - String.contains?(query, "X-Amz-Expires") do + if String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") do image else nil diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index bb5dda204..80082ea84 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do import Ecto.Query + require Pleroma.Constants + def create_status(%User{} = user, %{"status" => _} = data) do CommonAPI.post(user, data) end @@ -286,7 +288,7 @@ def search(_user, %{"q" => query} = params) do from( [a, o] in Activity.with_preloaded_object(Activity), where: fragment("?->>'type' = 'Create'", a.data), - where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, + where: ^Pleroma.Constants.as_public() in a.recipients, where: fragment( "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)", diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index e84af84dc..abae63877 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do import Ecto.Query require Logger + require Pleroma.Constants defp query_context_ids([]), do: [] @@ -91,7 +92,7 @@ defp get_user(ap_id, opts) do String.ends_with?(ap_id, "/followers") -> nil - ap_id == "https://www.w3.org/ns/activitystreams#Public" -> + ap_id == Pleroma.Constants.as_public() -> nil user = User.get_cached_by_ap_id(ap_id) -> diff --git a/lib/pleroma/web/twitter_api/views/notification_view.ex b/lib/pleroma/web/twitter_api/views/notification_view.ex index e7c7a7496..085cd5aa3 100644 --- a/lib/pleroma/web/twitter_api/views/notification_view.ex +++ b/lib/pleroma/web/twitter_api/views/notification_view.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do alias Pleroma.Web.TwitterAPI.ActivityView alias Pleroma.Web.TwitterAPI.UserView + require Pleroma.Constants + defp get_user(ap_id, opts) do cond do user = opts[:users][ap_id] -> @@ -18,7 +20,7 @@ defp get_user(ap_id, opts) do String.ends_with?(ap_id, "/followers") -> nil - ap_id == "https://www.w3.org/ns/activitystreams#Public" -> + ap_id == Pleroma.Constants.as_public() -> nil true -> diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index 1e948086a..e2f89f40a 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -124,8 +124,7 @@ test "renders body for follow activity" do {:ok, _, _, activity} = CommonAPI.follow(user, other_user) object = Object.normalize(activity) - assert Impl.format_body(%{activity: activity}, user, object) == - "@Bob has followed you" + assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you" end test "renders body for announce activity" do @@ -156,7 +155,6 @@ test "renders body for like activity" do {:ok, activity, _} = CommonAPI.favorite(activity.id, user) object = Object.normalize(activity) - assert Impl.format_body(%{activity: activity}, user, object) == - "@Bob has favorited your post" + assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post" end end From 159bbec570c308bf3d71487726737a91eb569178 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 29 Jul 2019 05:02:20 +0000 Subject: [PATCH 052/202] added tests for OstatusController --- lib/pleroma/web/ostatus/ostatus_controller.ex | 170 +++-- test/web/ostatus/ostatus_controller_test.exs | 630 ++++++++++++++---- 2 files changed, 585 insertions(+), 215 deletions(-) diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 372d52899..c70063b84 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do use Pleroma.Web, :controller + alias Fallback.RedirectController alias Pleroma.Activity alias Pleroma.Object alias Pleroma.User @@ -12,42 +13,44 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Endpoint alias Pleroma.Web.Federator + alias Pleroma.Web.Metadata.PlayerView alias Pleroma.Web.OStatus alias Pleroma.Web.OStatus.ActivityRepresenter alias Pleroma.Web.OStatus.FeedRepresenter + alias Pleroma.Web.Router alias Pleroma.Web.XML plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming]) + plug( + Pleroma.Plugs.SetFormatPlug + when action in [:feed_redirect, :object, :activity, :notice] + ) + action_fallback(:errors) + def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do + with {_, %User{} = user} <- + {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do + RedirectController.redirector_with_meta(conn, %{user: user}) + end + end + + def feed_redirect(%{assigns: %{format: format}} = conn, _params) + when format in ["json", "activity+json"] do + ActivityPubController.call(conn, :user) + end + def feed_redirect(conn, %{"nickname" => nickname}) do - case get_format(conn) do - "html" -> - with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do - Fallback.RedirectController.redirector_with_meta(conn, %{user: user}) - else - nil -> {:error, :not_found} - end - - "activity+json" -> - ActivityPubController.call(conn, :user) - - "json" -> - ActivityPubController.call(conn, :user) - - _ -> - with %User{} = user <- User.get_cached_by_nickname(nickname) do - redirect(conn, external: OStatus.feed_path(user)) - else - nil -> {:error, :not_found} - end + with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do + redirect(conn, external: OStatus.feed_path(user)) end end def feed(conn, %{"nickname" => nickname} = params) do - with %User{} = user <- User.get_cached_by_nickname(nickname) do + with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do query_params = Map.take(params, ["max_id"]) |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id}) @@ -65,8 +68,6 @@ def feed(conn, %{"nickname" => nickname} = params) do conn |> put_resp_content_type("application/atom+xml") |> send_resp(200, response) - else - nil -> {:error, :not_found} end end @@ -97,93 +98,82 @@ def salmon_incoming(conn, _) do |> send_resp(200, "") end - def object(conn, %{"uuid" => uuid}) do - if get_format(conn) in ["activity+json", "json"] do - ActivityPubController.call(conn, :object) - else - with id <- o_status_url(conn, :object, uuid), - {_, %Activity{} = activity} <- - {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - case get_format(conn) do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, nil, activity, user) - end - else - {:public?, false} -> - {:error, :not_found} + def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) + when format in ["json", "activity+json"] do + ActivityPubController.call(conn, :object) + end - {:activity, nil} -> - {:error, :not_found} - - e -> - e + def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do + with id <- o_status_url(conn, :object, uuid), + {_, %Activity{} = activity} <- + {:activity, Activity.get_create_by_object_ap_id_with_object(id)}, + {_, true} <- {:public?, Visibility.is_public?(activity)}, + %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + case format do + "html" -> redirect(conn, to: "/notice/#{activity.id}") + _ -> represent_activity(conn, nil, activity, user) end + else + reason when reason in [{:public?, false}, {:activity, nil}] -> + {:error, :not_found} + + e -> + e end end - def activity(conn, %{"uuid" => uuid}) do - if get_format(conn) in ["activity+json", "json"] do - ActivityPubController.call(conn, :activity) - else - with id <- o_status_url(conn, :activity, uuid), - {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, - {_, true} <- {:public?, Visibility.is_public?(activity)}, - %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - case format = get_format(conn) do - "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, format, activity, user) - end - else - {:public?, false} -> - {:error, :not_found} + def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) + when format in ["json", "activity+json"] do + ActivityPubController.call(conn, :activity) + end - {:activity, nil} -> - {:error, :not_found} - - e -> - e + def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do + with id <- o_status_url(conn, :activity, uuid), + {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, + {_, true} <- {:public?, Visibility.is_public?(activity)}, + %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do + case format do + "html" -> redirect(conn, to: "/notice/#{activity.id}") + _ -> represent_activity(conn, format, activity, user) end + else + reason when reason in [{:public?, false}, {:activity, nil}] -> + {:error, :not_found} + + e -> + e end end - def notice(conn, %{"id" => id}) do + def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)}, {_, true} <- {:public?, Visibility.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - case format = get_format(conn) do - "html" -> - if activity.data["type"] == "Create" do - %Object{} = object = Object.normalize(activity) + cond do + format == "html" && activity.data["type"] == "Create" -> + %Object{} = object = Object.normalize(activity) - Fallback.RedirectController.redirector_with_meta(conn, %{ + RedirectController.redirector_with_meta( + conn, + %{ activity_id: activity.id, object: object, - url: - Pleroma.Web.Router.Helpers.o_status_url( - Pleroma.Web.Endpoint, - :notice, - activity.id - ), + url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), user: user - }) - else - Fallback.RedirectController.redirector(conn, nil) - end + } + ) - _ -> + format == "html" -> + RedirectController.redirector(conn, nil) + + true -> represent_activity(conn, format, activity, user) end else - {:public?, false} -> + reason when reason in [{:public?, false}, {:activity, nil}] -> conn |> put_status(404) - |> Fallback.RedirectController.redirector(nil, 404) - - {:activity, nil} -> - conn - |> Fallback.RedirectController.redirector(nil, 404) + |> RedirectController.redirector(nil, 404) e -> e @@ -204,13 +194,13 @@ def notice_player(conn, %{"id" => id}) do "content-security-policy", "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;" ) - |> put_view(Pleroma.Web.Metadata.PlayerView) + |> put_view(PlayerView) |> render("player.html", url) else _error -> conn |> put_status(404) - |> Fallback.RedirectController.redirector(nil, 404) + |> RedirectController.redirector(nil, 404) end end @@ -248,6 +238,8 @@ def errors(conn, {:error, :not_found}) do render_error(conn, :not_found, "Not found") end + def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found}) + def errors(conn, _) do render_error(conn, :internal_server_error, "Something went wrong") end diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index bb7648bdd..9f756effb 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -101,160 +101,538 @@ test "returns 404 for a missing feed", %{conn: conn} do assert response(conn, 404) end - test "gets an object", %{conn: conn} do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - user = User.get_cached_by_ap_id(note_activity.data["actor"]) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - url = "/objects/#{uuid}" + describe "GET object/2" do + test "gets an object", %{conn: conn} do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + url = "/objects/#{uuid}" + + conn = + conn + |> put_req_header("accept", "application/xml") + |> get(url) + + expected = + ActivityRepresenter.to_simple_form(note_activity, user, true) + |> ActivityRepresenter.wrap_with_entry() + |> :xmerl.export_simple(:xmerl_xml) + |> to_string + + assert response(conn, 200) == expected + end + + test "redirects to /notice/id for html format", %{conn: conn} do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + url = "/objects/#{uuid}" + + conn = + conn + |> put_req_header("accept", "text/html") + |> get(url) + + assert redirected_to(conn) == "/notice/#{note_activity.id}" + end + + test "500s when user not found", %{conn: conn} do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + User.invalidate_cache(user) + Pleroma.Repo.delete(user) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + url = "/objects/#{uuid}" + + conn = + conn + |> put_req_header("accept", "application/xml") + |> get(url) + + assert response(conn, 500) == ~S({"error":"Something went wrong"}) + end + + test "404s on private objects", %{conn: conn} do + note_activity = insert(:direct_note_activity) + object = Object.normalize(note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + + conn + |> get("/objects/#{uuid}") + |> response(404) + end + + test "404s on nonexisting objects", %{conn: conn} do + conn + |> get("/objects/123") + |> response(404) + end + end + + describe "GET activity/2" do + test "gets an activity in xml format", %{conn: conn} do + note_activity = insert(:note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - conn = conn |> put_req_header("accept", "application/xml") - |> get(url) + |> get("/activities/#{uuid}") + |> response(200) + end - expected = - ActivityRepresenter.to_simple_form(note_activity, user, true) - |> ActivityRepresenter.wrap_with_entry() - |> :xmerl.export_simple(:xmerl_xml) - |> to_string + test "redirects to /notice/id for html format", %{conn: conn} do + note_activity = insert(:note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - assert response(conn, 200) == expected + conn = + conn + |> put_req_header("accept", "text/html") + |> get("/activities/#{uuid}") + + assert redirected_to(conn) == "/notice/#{note_activity.id}" + end + + test "505s when user not found", %{conn: conn} do + note_activity = insert(:note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + User.invalidate_cache(user) + Pleroma.Repo.delete(user) + + conn = + conn + |> put_req_header("accept", "text/html") + |> get("/activities/#{uuid}") + + assert response(conn, 500) == ~S({"error":"Something went wrong"}) + end + + test "404s on deleted objects", %{conn: conn} do + note_activity = insert(:note_activity) + object = Object.normalize(note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + + conn + |> put_req_header("accept", "application/xml") + |> get("/objects/#{uuid}") + |> response(200) + + Object.delete(object) + + conn + |> put_req_header("accept", "application/xml") + |> get("/objects/#{uuid}") + |> response(404) + end + + test "404s on private activities", %{conn: conn} do + note_activity = insert(:direct_note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) + + conn + |> get("/activities/#{uuid}") + |> response(404) + end + + test "404s on nonexistent activities", %{conn: conn} do + conn + |> get("/activities/123") + |> response(404) + end + + test "gets an activity in AS2 format", %{conn: conn} do + note_activity = insert(:note_activity) + [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) + url = "/activities/#{uuid}" + + conn = + conn + |> put_req_header("accept", "application/activity+json") + |> get(url) + + assert json_response(conn, 200) + end end - test "404s on private objects", %{conn: conn} do - note_activity = insert(:direct_note_activity) - object = Object.normalize(note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) + describe "GET notice/2" do + test "gets a notice in xml format", %{conn: conn} do + note_activity = insert(:note_activity) - conn - |> get("/objects/#{uuid}") - |> response(404) - end + conn + |> get("/notice/#{note_activity.id}") + |> response(200) + end - test "404s on nonexisting objects", %{conn: conn} do - conn - |> get("/objects/123") - |> response(404) - end + test "gets a notice in AS2 format", %{conn: conn} do + note_activity = insert(:note_activity) - test "gets an activity in xml format", %{conn: conn} do - note_activity = insert(:note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - - conn - |> put_req_header("accept", "application/xml") - |> get("/activities/#{uuid}") - |> response(200) - end - - test "404s on deleted objects", %{conn: conn} do - note_activity = insert(:note_activity) - object = Object.normalize(note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"])) - - conn - |> put_req_header("accept", "application/xml") - |> get("/objects/#{uuid}") - |> response(200) - - Object.delete(object) - - conn - |> put_req_header("accept", "application/xml") - |> get("/objects/#{uuid}") - |> response(404) - end - - test "404s on private activities", %{conn: conn} do - note_activity = insert(:direct_note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - - conn - |> get("/activities/#{uuid}") - |> response(404) - end - - test "404s on nonexistent activities", %{conn: conn} do - conn - |> get("/activities/123") - |> response(404) - end - - test "gets a notice in xml format", %{conn: conn} do - note_activity = insert(:note_activity) - - conn - |> get("/notice/#{note_activity.id}") - |> response(200) - end - - test "gets a notice in AS2 format", %{conn: conn} do - note_activity = insert(:note_activity) - - conn - |> put_req_header("accept", "application/activity+json") - |> get("/notice/#{note_activity.id}") - |> json_response(200) - end - - test "only gets a notice in AS2 format for Create messages", %{conn: conn} do - note_activity = insert(:note_activity) - url = "/notice/#{note_activity.id}" - - conn = conn |> put_req_header("accept", "application/activity+json") - |> get(url) + |> get("/notice/#{note_activity.id}") + |> json_response(200) + end - assert json_response(conn, 200) + test "500s when actor not found", %{conn: conn} do + note_activity = insert(:note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + User.invalidate_cache(user) + Pleroma.Repo.delete(user) - user = insert(:user) + conn = + conn + |> get("/notice/#{note_activity.id}") - {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user) - url = "/notice/#{like_activity.id}" + assert response(conn, 500) == ~S({"error":"Something went wrong"}) + end - assert like_activity.data["type"] == "Like" + test "only gets a notice in AS2 format for Create messages", %{conn: conn} do + note_activity = insert(:note_activity) + url = "/notice/#{note_activity.id}" - conn = - build_conn() - |> put_req_header("accept", "application/activity+json") - |> get(url) + conn = + conn + |> put_req_header("accept", "application/activity+json") + |> get(url) - assert response(conn, 404) + assert json_response(conn, 200) + + user = insert(:user) + + {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user) + url = "/notice/#{like_activity.id}" + + assert like_activity.data["type"] == "Like" + + conn = + build_conn() + |> put_req_header("accept", "application/activity+json") + |> get(url) + + assert response(conn, 404) + end + + test "render html for redirect for html format", %{conn: conn} do + note_activity = insert(:note_activity) + + resp = + conn + |> put_req_header("accept", "text/html") + |> get("/notice/#{note_activity.id}") + |> response(200) + + assert resp =~ + "" + + user = insert(:user) + + {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user) + + assert like_activity.data["type"] == "Like" + + resp = + conn + |> put_req_header("accept", "text/html") + |> get("/notice/#{like_activity.id}") + |> response(200) + + assert resp =~ "" + end + + test "404s a private notice", %{conn: conn} do + note_activity = insert(:direct_note_activity) + url = "/notice/#{note_activity.id}" + + conn = + conn + |> get(url) + + assert response(conn, 404) + end + + test "404s a nonexisting notice", %{conn: conn} do + url = "/notice/123" + + conn = + conn + |> get(url) + + assert response(conn, 404) + end end - test "gets an activity in AS2 format", %{conn: conn} do - note_activity = insert(:note_activity) - [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) - url = "/activities/#{uuid}" + describe "feed_redirect" do + test "undefined format. it redirects to feed", %{conn: conn} do + note_activity = insert(:note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) - conn = - conn - |> put_req_header("accept", "application/activity+json") - |> get(url) + response = + conn + |> put_req_header("accept", "application/xml") + |> get("/users/#{user.nickname}") + |> response(302) - assert json_response(conn, 200) + assert response == + "You are being redirected." + end + + test "undefined format. it returns error when user not found", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/xml") + |> get("/users/jimm") + |> response(404) + + assert response == ~S({"error":"Not found"}) + end + + test "activity+json format. it redirects on actual feed of user", %{conn: conn} do + note_activity = insert(:note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + + response = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/users/#{user.nickname}") + |> json_response(200) + + assert response["endpoints"] == %{ + "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", + "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", + "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", + "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox" + } + + assert response["@context"] == [ + "https://www.w3.org/ns/activitystreams", + "http://localhost:4001/schemas/litepub-0.1.jsonld", + %{"@language" => "und"} + ] + + assert Map.take(response, [ + "followers", + "following", + "id", + "inbox", + "manuallyApprovesFollowers", + "name", + "outbox", + "preferredUsername", + "summary", + "tag", + "type", + "url" + ]) == %{ + "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", + "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", + "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", + "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", + "manuallyApprovesFollowers" => false, + "name" => user.name, + "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", + "preferredUsername" => user.nickname, + "summary" => user.bio, + "tag" => [], + "type" => "Person", + "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" + } + end + + test "activity+json format. it returns error whe use not found", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/users/jimm") + |> json_response(404) + + assert response == "Not found" + end + + test "json format. it redirects on actual feed of user", %{conn: conn} do + note_activity = insert(:note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + + response = + conn + |> put_req_header("accept", "application/json") + |> get("/users/#{user.nickname}") + |> json_response(200) + + assert response["endpoints"] == %{ + "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", + "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", + "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", + "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox" + } + + assert response["@context"] == [ + "https://www.w3.org/ns/activitystreams", + "http://localhost:4001/schemas/litepub-0.1.jsonld", + %{"@language" => "und"} + ] + + assert Map.take(response, [ + "followers", + "following", + "id", + "inbox", + "manuallyApprovesFollowers", + "name", + "outbox", + "preferredUsername", + "summary", + "tag", + "type", + "url" + ]) == %{ + "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", + "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", + "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", + "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", + "manuallyApprovesFollowers" => false, + "name" => user.name, + "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", + "preferredUsername" => user.nickname, + "summary" => user.bio, + "tag" => [], + "type" => "Person", + "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" + } + end + + test "json format. it returns error whe use not found", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/json") + |> get("/users/jimm") + |> json_response(404) + + assert response == "Not found" + end + + test "html format. it redirects on actual feed of user", %{conn: conn} do + note_activity = insert(:note_activity) + user = User.get_cached_by_ap_id(note_activity.data["actor"]) + + response = + conn + |> get("/users/#{user.nickname}") + |> response(200) + + assert response == + Fallback.RedirectController.redirector_with_meta( + conn, + %{user: user} + ).resp_body + end + + test "html format. it returns error when user not found", %{conn: conn} do + response = + conn + |> get("/users/jimm") + |> json_response(404) + + assert response == %{"error" => "Not found"} + end end - test "404s a private notice", %{conn: conn} do - note_activity = insert(:direct_note_activity) - url = "/notice/#{note_activity.id}" + describe "GET /notice/:id/embed_player" do + test "render embed player", %{conn: conn} do + note_activity = insert(:note_activity) + object = Pleroma.Object.normalize(note_activity) - conn = - conn - |> get(url) + object_data = + Map.put(object.data, "attachment", [ + %{ + "url" => [ + %{ + "href" => + "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", + "mediaType" => "video/mp4", + "type" => "Link" + } + ] + } + ]) - assert response(conn, 404) - end + object + |> Ecto.Changeset.change(data: object_data) + |> Pleroma.Repo.update() - test "404s a nonexisting notice", %{conn: conn} do - url = "/notice/123" + conn = + conn + |> get("/notice/#{note_activity.id}/embed_player") - conn = - conn - |> get(url) + assert Plug.Conn.get_resp_header(conn, "x-frame-options") == ["ALLOW"] - assert response(conn, 404) + assert Plug.Conn.get_resp_header( + conn, + "content-security-policy" + ) == [ + "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;" + ] + + assert response(conn, 200) =~ + "" + end + + test "404s when activity isn't create", %{conn: conn} do + note_activity = insert(:note_activity, data_attrs: %{"type" => "Like"}) + + assert conn + |> get("/notice/#{note_activity.id}/embed_player") + |> response(404) + end + + test "404s when activity is direct message", %{conn: conn} do + note_activity = insert(:note_activity, data_attrs: %{"directMessage" => true}) + + assert conn + |> get("/notice/#{note_activity.id}/embed_player") + |> response(404) + end + + test "404s when attachment is empty", %{conn: conn} do + note_activity = insert(:note_activity) + object = Pleroma.Object.normalize(note_activity) + object_data = Map.put(object.data, "attachment", []) + + object + |> Ecto.Changeset.change(data: object_data) + |> Pleroma.Repo.update() + + assert conn + |> get("/notice/#{note_activity.id}/embed_player") + |> response(404) + end + + test "404s when attachment isn't audio or video", %{conn: conn} do + note_activity = insert(:note_activity) + object = Pleroma.Object.normalize(note_activity) + + object_data = + Map.put(object.data, "attachment", [ + %{ + "url" => [ + %{ + "href" => "https://peertube.moe/static/webseed/480.jpg", + "mediaType" => "image/jpg", + "type" => "Link" + } + ] + } + ]) + + object + |> Ecto.Changeset.change(data: object_data) + |> Pleroma.Repo.update() + + assert conn + |> get("/notice/#{note_activity.id}/embed_player") + |> response(404) + end end end From c0e258cf21395fa2d5338ee238e4fcf4f3b3bf30 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Mon, 29 Jul 2019 16:17:22 +0000 Subject: [PATCH 053/202] Redirect not logged-in users to the MastoFE login page on private instances --- CHANGELOG.md | 1 + lib/pleroma/web/router.ex | 2 +- .../mastodon_api/mastodon_api_controller_test.exs | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48379b757..5416d452e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Rich Media: The crawled URL is now spliced into the rich media data. - ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification. - ActivityPub S2S: remote user deletions now work the same as local user deletions. +- Not being able to access the Mastodon FE login page on private instances ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4e1ab6c33..0689d69fb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -698,7 +698,7 @@ defmodule Pleroma.Web.Router do post("/auth/password", MastodonAPIController, :password_reset) scope [] do - pipe_through(:oauth_read_or_public) + pipe_through(:oauth_read) get("/web/*path", MastodonAPIController, :index) end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index d7f92fac2..66016c886 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -3154,6 +3154,21 @@ test "redirects not logged-in users to the login page", %{conn: conn, path: path assert redirected_to(conn) == "/web/login" end + test "redirects not logged-in users to the login page on private instances", %{ + conn: conn, + path: path + } do + is_public = Pleroma.Config.get([:instance, :public]) + Pleroma.Config.put([:instance, :public], false) + + conn = get(conn, path) + + assert conn.status == 302 + assert redirected_to(conn) == "/web/login" + + Pleroma.Config.put([:instance, :public], is_public) + end + test "does not redirect logged in users to the login page", %{conn: conn, path: path} do token = insert(:oauth_token) From 0bee2131ce55ffd702ddc92800499b01b86d3765 Mon Sep 17 00:00:00 2001 From: Eugenij Date: Mon, 29 Jul 2019 16:17:40 +0000 Subject: [PATCH 054/202] Add `mailerEnabled` to the NodeInfo metadata --- CHANGELOG.md | 1 + lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5416d452e..e77fe4f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set - NodeInfo: Return `skipThreadContainment` in `metadata` for the `skip_thread_containment` option +- NodeInfo: Return `mailerEnabled` in `metadata` - Mastodon API: Unsubscribe followers when they unfollow a user - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index a1d7fcc7d..54f89e65c 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -165,6 +165,7 @@ def raw_nodeinfo do }, accountActivationRequired: Config.get([:instance, :account_activation_required], false), invitesEnabled: Config.get([:instance, :invites_enabled], false), + mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false), features: features, restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]), skipThreadContainment: Config.get([:instance, :skip_thread_containment], false) From 5795a890e9d14a9e51e2613d26620899b2171623 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 29 Jul 2019 19:09:58 +0000 Subject: [PATCH 055/202] markdown: clean up html generated by earmark --- lib/pleroma/web/common_api/utils.ex | 3 +++ test/web/common_api/common_api_utils_test.exs | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index d80fffa26..6d42ae8ae 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -300,6 +300,9 @@ def format_input(text, "text/markdown", options) do |> Earmark.as_html!() |> Formatter.linkify(options) |> Formatter.html_escape("text/html") + |> (fn {text, mentions, tags} -> + {String.replace(text, ~r/\r?\n/, ""), mentions, tags} + end).() end def make_note_data( diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index af320f31f..38b2319ac 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -99,14 +99,14 @@ test "works for bare text/html" do test "works for bare text/markdown" do text = "**hello world**" - expected = "

hello world

\n" + expected = "

hello world

" {output, [], []} = Utils.format_input(text, "text/markdown") assert output == expected text = "**hello world**\n\n*another paragraph*" - expected = "

hello world

\n

another paragraph

\n" + expected = "

hello world

another paragraph

" {output, [], []} = Utils.format_input(text, "text/markdown") @@ -118,7 +118,7 @@ test "works for bare text/markdown" do by someone """ - expected = "

cool quote

\n
\n

by someone

\n" + expected = "

cool quote

by someone

" {output, [], []} = Utils.format_input(text, "text/markdown") @@ -157,11 +157,11 @@ test "works for text/markdown with mentions" do text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*" expected = - "

hello world

\n

another hello world

another @user__test and @user__test google.com paragraph

\n" + }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@user__test google.com paragraph

" {output, _, _} = Utils.format_input(text, "text/markdown") From 5835069215b880ad261a006cf310da624a82ca4a Mon Sep 17 00:00:00 2001 From: kaniini Date: Mon, 29 Jul 2019 19:42:26 +0000 Subject: [PATCH 056/202] Revert "Merge branch 'bugfix/clean-up-markdown-rendering' into 'develop'" This reverts merge request !1504 --- lib/pleroma/web/common_api/utils.ex | 3 --- test/web/common_api/common_api_utils_test.exs | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 6d42ae8ae..d80fffa26 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -300,9 +300,6 @@ def format_input(text, "text/markdown", options) do |> Earmark.as_html!() |> Formatter.linkify(options) |> Formatter.html_escape("text/html") - |> (fn {text, mentions, tags} -> - {String.replace(text, ~r/\r?\n/, ""), mentions, tags} - end).() end def make_note_data( diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 38b2319ac..af320f31f 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -99,14 +99,14 @@ test "works for bare text/html" do test "works for bare text/markdown" do text = "**hello world**" - expected = "

hello world

" + expected = "

hello world

\n" {output, [], []} = Utils.format_input(text, "text/markdown") assert output == expected text = "**hello world**\n\n*another paragraph*" - expected = "

hello world

another paragraph

" + expected = "

hello world

\n

another paragraph

\n" {output, [], []} = Utils.format_input(text, "text/markdown") @@ -118,7 +118,7 @@ test "works for bare text/markdown" do by someone """ - expected = "

cool quote

by someone

" + expected = "

cool quote

\n
\n

by someone

\n" {output, [], []} = Utils.format_input(text, "text/markdown") @@ -157,11 +157,11 @@ test "works for text/markdown with mentions" do text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*" expected = - "

hello world

another hello world

\n

another @user__test and @user__test google.com paragraph

" + }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@user__test google.com paragraph

\n" {output, _, _} = Utils.format_input(text, "text/markdown") From 3850812503ebfe0e1eaf84a4067e11e052a8206e Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 29 Jul 2019 20:00:57 +0000 Subject: [PATCH 057/202] twitter api: utils: rework do_remote_follow() to use CommonAPI Closes #1138 --- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 39bc6147c..5c73a615d 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -15,7 +15,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Plugs.AuthenticationPlug alias Pleroma.User alias Pleroma.Web - alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.WebFinger @@ -100,8 +99,7 @@ def do_remote_follow(conn, %{ with %User{} = user <- User.get_cached_by_nickname(username), true <- AuthenticationPlug.checkpw(password, user.password_hash), %User{} = _followed <- User.get_cached_by_id(id), - {:ok, follower} <- User.follow(user, followee), - {:ok, _activity} <- ActivityPub.follow(follower, followee) do + {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do conn |> render("followed.html", %{error: false}) else @@ -122,8 +120,7 @@ def do_remote_follow(conn, %{ def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do with %User{} = followee <- User.get_cached_by_id(id), - {:ok, follower} <- User.follow(user, followee), - {:ok, _activity} <- ActivityPub.follow(follower, followee) do + {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do conn |> render("followed.html", %{error: false}) else From 51b3b6d8164de9196159dc7de8d5abf0c4fa1bce Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Tue, 30 Jul 2019 16:36:05 +0000 Subject: [PATCH 058/202] Admin changes --- CHANGELOG.md | 1 + docs/api/admin_api.md | 23 ++++++++++++ lib/mix/tasks/pleroma/config.ex | 2 +- .../web/admin_api/admin_api_controller.ex | 10 +++++ lib/pleroma/web/router.ex | 2 + .../admin_api/admin_api_controller_test.exs | 37 +++++++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e77fe4f3d..acd55362d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Return avatar and display name when querying users - Admin API: Allow querying user by ID - Admin API: Added support for `tuples`. +- Admin API: Added endpoints to run mix tasks pleroma.config migrate_to_db & pleroma.config migrate_from_db - Added synchronization of following/followers counters for external users - Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`. - Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options. diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index ca9303227..22873dde9 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -575,6 +575,29 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret - 404 Not Found `"Not found"` - On success: 200 OK `{}` + +## `/api/pleroma/admin/config/migrate_to_db` +### Run mix task pleroma.config migrate_to_db +Copy settings on key `:pleroma` to DB. +- Method `GET` +- Params: none +- Response: + +```json +{} +``` + +## `/api/pleroma/admin/config/migrate_from_db` +### Run mix task pleroma.config migrate_from_db +Copy all settings from DB to `config/prod.exported_from_db.secret.exs` with deletion from DB. +- Method `GET` +- Params: none +- Response: + +```json +{} +``` + ## `/api/pleroma/admin/config` ### List config settings List config settings only works with `:pleroma => :instance => :dynamic_configuration` setting to `true`. diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index a7d0fac5d..462940e7e 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -15,7 +15,7 @@ defmodule Mix.Tasks.Pleroma.Config do mix pleroma.config migrate_to_db - ## Transfers config from DB to file. + ## Transfers config from DB to file `config/env.exported_from_db.secret.exs` mix pleroma.config migrate_from_db ENV """ diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 1ae5acd91..fcda57b3e 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -379,6 +379,16 @@ def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end + def migrate_to_db(conn, _params) do + Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) + json(conn, %{}) + end + + def migrate_from_db(conn, _params) do + Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"]) + json(conn, %{}) + end + def config_show(conn, _params) do configs = Pleroma.Repo.all(Config) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 0689d69fb..d475fc973 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -196,6 +196,8 @@ defmodule Pleroma.Web.Router do get("/config", AdminAPIController, :config_show) post("/config", AdminAPIController, :config_update) + get("/config/migrate_to_db", AdminAPIController, :migrate_to_db) + get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) end scope "/", Pleroma.Web.TwitterAPI do diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 6dda4ae51..824ad23e6 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1916,6 +1916,43 @@ test "queues key as atom", %{conn: conn} do end end + describe "config mix tasks run" do + setup %{conn: conn} do + admin = insert(:user, info: %{is_admin: true}) + + temp_file = "config/test.exported_from_db.secret.exs" + + on_exit(fn -> + :ok = File.rm(temp_file) + end) + + dynamic = Pleroma.Config.get([:instance, :dynamic_configuration]) + + Pleroma.Config.put([:instance, :dynamic_configuration], true) + + on_exit(fn -> + Pleroma.Config.put([:instance, :dynamic_configuration], dynamic) + end) + + %{conn: assign(conn, :user, admin), admin: admin} + end + + test "transfer settings to DB and to file", %{conn: conn, admin: admin} do + assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] + conn = get(conn, "/api/pleroma/admin/config/migrate_to_db") + assert json_response(conn, 200) == %{} + assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0 + + conn = + build_conn() + |> assign(:user, admin) + |> get("/api/pleroma/admin/config/migrate_from_db") + + assert json_response(conn, 200) == %{} + assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == [] + end + end + describe "GET /api/pleroma/admin/users/:nickname/statuses" do setup do admin = insert(:user, info: %{is_admin: true}) From f42719506c539a4058c52d3a6e4a828948ac74ce Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 31 Jul 2019 14:20:34 +0300 Subject: [PATCH 059/202] Fix credo issues --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fd1c0a544..7acf1e53c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -741,7 +741,7 @@ def fetch_follow_information(user) do end def update_follower_count(%User{} = user) do - unless user.local == false and Pleroma.Config.get([:instance, :external_user_synchronization]) do + unless !user.local and Pleroma.Config.get([:instance, :external_user_synchronization]) do follower_count_query = User.Query.build(%{followers: user, deactivated: false}) |> select([u], %{count: count(u.id)}) From 7483679a7b6ff63c9c61c3df3e9e37f2c24012ff Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 31 Jul 2019 15:12:29 +0200 Subject: [PATCH 060/202] StatusView: Return direct conversation id. --- lib/pleroma/conversation/participation.ex | 8 ++++++++ .../web/mastodon_api/views/status_view.ex | 18 +++++++++++++++++- test/web/mastodon_api/status_view_test.exs | 18 +++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 5883e4183..77b3f61e9 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -65,6 +65,14 @@ def for_user(user, params \\ %{}) do |> Pleroma.Pagination.fetch_paginated(params) end + def for_user_and_conversation(user, conversation) do + from(p in __MODULE__, + where: p.user_id == ^user.id, + where: p.conversation_id == ^conversation.id + ) + |> Repo.one() + end + def for_user_with_last_activity_id(user, params \\ %{}) do for_user(user, params) |> Enum.map(fn participation -> diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 80df9b2ac..a862554b1 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -6,6 +6,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do use Pleroma.Web, :view alias Pleroma.Activity + alias Pleroma.Conversation + alias Pleroma.Conversation.Participation alias Pleroma.HTML alias Pleroma.Object alias Pleroma.Repo @@ -225,6 +227,19 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity object.data["url"] || object.data["external_url"] || object.data["id"] end + direct_conversation_id = + with {_, true} <- {:include_id, opts[:with_direct_conversation_id]}, + {_, %User{} = for_user} <- {:for_user, opts[:for]}, + %{data: %{"context" => context}} when is_binary(context) <- activity, + %Conversation{} = conversation <- Conversation.get_for_ap_id(context), + %Participation{id: participation_id} <- + Participation.for_user_and_conversation(for_user, conversation) do + participation_id + else + _e -> + nil + end + %{ id: to_string(activity.id), uri: object.data["id"], @@ -262,7 +277,8 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity conversation_id: get_context_id(activity), in_reply_to_account_acct: reply_to_user && reply_to_user.nickname, content: %{"text/plain" => content_plaintext}, - spoiler_text: %{"text/plain" => summary_plaintext} + spoiler_text: %{"text/plain" => summary_plaintext}, + direct_conversation_id: direct_conversation_id } } end diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs index 0b167f839..c983b494f 100644 --- a/test/web/mastodon_api/status_view_test.exs +++ b/test/web/mastodon_api/status_view_test.exs @@ -23,6 +23,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do :ok end + test "returns the direct conversation id when given the `with_conversation_id` option" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"}) + + status = + StatusView.render("status.json", + activity: activity, + with_direct_conversation_id: true, + for: user + ) + + assert status[:pleroma][:direct_conversation_id] + end + test "returns a temporary ap_id based user for activities missing db users" do user = insert(:user) @@ -133,7 +148,8 @@ test "a note activity" do conversation_id: convo_id, in_reply_to_account_acct: nil, content: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["content"])}, - spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])} + spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])}, + direct_conversation_id: nil } } From 58443d0cd683c227199eb34d660191292e487a14 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 31 Jul 2019 15:14:36 +0000 Subject: [PATCH 061/202] tests for TwitterApi/UtilController --- lib/pleroma/user.ex | 2 + .../controllers/util_controller.ex | 186 ++++---- test/support/http_request_mock.ex | 4 + test/web/twitter_api/util_controller_test.exs | 404 +++++++++++++++++- 4 files changed, 503 insertions(+), 93 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6e2fd3af8..1adb82f32 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -226,6 +226,7 @@ def password_update_changeset(struct, params) do |> put_password_hash end + @spec reset_password(User.t(), map) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} def reset_password(%User{id: user_id} = user, data) do multi = Multi.new() @@ -330,6 +331,7 @@ def needs_update?(%User{local: false} = user) do def needs_update?(_), do: true + @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()} def maybe_direct_follow(%User{} = follower, %User{local: true, info: %{locked: true}}) do {:ok, follower} end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 5c73a615d..3405bd3b7 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -18,6 +18,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.WebFinger + plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version]) + def help_test(conn, _params) do json(conn, "ok") end @@ -58,27 +60,25 @@ def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"]) redirect(conn, to: "/notice/#{activity_id}") else - {err, followee} = User.get_or_fetch(acct) - avatar = User.avatar_url(followee) - name = followee.nickname - id = followee.id - - if !!user do + with {:ok, followee} <- User.get_or_fetch(acct) do conn - |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id}) - else - conn - |> render("follow_login.html", %{ + |> render(follow_template(user), %{ error: false, acct: acct, - avatar: avatar, - name: name, - id: id + avatar: User.avatar_url(followee), + name: followee.nickname, + id: followee.id }) + else + {:error, _reason} -> + render(conn, follow_template(user), %{error: :error}) end end end + defp follow_template(%User{} = _user), do: "follow.html" + defp follow_template(_), do: "follow_login.html" + defp is_status?(acct) do case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] -> @@ -92,48 +92,53 @@ defp is_status?(acct) do def do_remote_follow(conn, %{ "authorization" => %{"name" => username, "password" => password, "id" => id} }) do - followee = User.get_cached_by_id(id) - avatar = User.avatar_url(followee) - name = followee.nickname - - with %User{} = user <- User.get_cached_by_nickname(username), - true <- AuthenticationPlug.checkpw(password, user.password_hash), - %User{} = _followed <- User.get_cached_by_id(id), + with %User{} = followee <- User.get_cached_by_id(id), + {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee}, + {_, true, _} <- { + :auth, + AuthenticationPlug.checkpw(password, user.password_hash), + followee + }, {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do conn |> render("followed.html", %{error: false}) else # Was already following user {:error, "Could not follow user:" <> _rest} -> - render(conn, "followed.html", %{error: false}) + render(conn, "followed.html", %{error: "Error following account"}) - _e -> + {:auth, _, followee} -> conn |> render("follow_login.html", %{ error: "Wrong username or password", id: id, - name: name, - avatar: avatar + name: followee.nickname, + avatar: User.avatar_url(followee) }) + + e -> + Logger.debug("Remote follow failed with error #{inspect(e)}") + render(conn, "followed.html", %{error: "Something went wrong."}) end end def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do - with %User{} = followee <- User.get_cached_by_id(id), + with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do conn |> render("followed.html", %{error: false}) else # Was already following user {:error, "Could not follow user:" <> _rest} -> - conn - |> render("followed.html", %{error: false}) + render(conn, "followed.html", %{error: "Error following account"}) + + {:fetch_user, error} -> + Logger.debug("Remote follow failed with error #{inspect(error)}") + render(conn, "followed.html", %{error: "Could not find user"}) e -> Logger.debug("Remote follow failed with error #{inspect(e)}") - - conn - |> render("followed.html", %{error: inspect(e)}) + render(conn, "followed.html", %{error: "Something went wrong."}) end end @@ -148,67 +153,70 @@ def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_ end end + def config(%{assigns: %{format: "xml"}} = conn, _params) do + instance = Pleroma.Config.get(:instance) + + response = """ + + + #{Keyword.get(instance, :name)} + #{Web.base_url()} + #{Keyword.get(instance, :limit)} + #{!Keyword.get(instance, :registrations_open)} + + + """ + + conn + |> put_resp_content_type("application/xml") + |> send_resp(200, response) + end + def config(conn, _params) do instance = Pleroma.Config.get(:instance) - case get_format(conn) do - "xml" -> - response = """ - - - #{Keyword.get(instance, :name)} - #{Web.base_url()} - #{Keyword.get(instance, :limit)} - #{!Keyword.get(instance, :registrations_open)} - - - """ + vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key) - conn - |> put_resp_content_type("application/xml") - |> send_resp(200, response) + uploadlimit = %{ + uploadlimit: to_string(Keyword.get(instance, :upload_limit)), + avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)), + backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)), + bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit)) + } - _ -> - vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key) + data = %{ + name: Keyword.get(instance, :name), + description: Keyword.get(instance, :description), + server: Web.base_url(), + textlimit: to_string(Keyword.get(instance, :limit)), + uploadlimit: uploadlimit, + closed: bool_to_val(Keyword.get(instance, :registrations_open), "0", "1"), + private: bool_to_val(Keyword.get(instance, :public, true), "0", "1"), + vapidPublicKey: vapid_public_key, + accountActivationRequired: + bool_to_val(Keyword.get(instance, :account_activation_required, false)), + invitesEnabled: bool_to_val(Keyword.get(instance, :invites_enabled, false)), + safeDMMentionsEnabled: bool_to_val(Pleroma.Config.get([:instance, :safe_dm_mentions])) + } - uploadlimit = %{ - uploadlimit: to_string(Keyword.get(instance, :upload_limit)), - avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)), - backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)), - bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit)) - } - - data = %{ - name: Keyword.get(instance, :name), - description: Keyword.get(instance, :description), - server: Web.base_url(), - textlimit: to_string(Keyword.get(instance, :limit)), - uploadlimit: uploadlimit, - closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"), - private: if(Keyword.get(instance, :public, true), do: "0", else: "1"), - vapidPublicKey: vapid_public_key, - accountActivationRequired: - if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"), - invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"), - safeDMMentionsEnabled: - if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0") - } + managed_config = Keyword.get(instance, :managed_config) + data = + if managed_config do pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe]) + Map.put(data, "pleromafe", pleroma_fe) + else + data + end - managed_config = Keyword.get(instance, :managed_config) - - data = - if managed_config do - data |> Map.put("pleromafe", pleroma_fe) - else - data - end - - json(conn, %{site: data}) - end + json(conn, %{site: data}) end + defp bool_to_val(true), do: "1" + defp bool_to_val(_), do: "0" + defp bool_to_val(true, val, _), do: val + defp bool_to_val(_, _, val), do: val + def frontend_configurations(conn, _params) do config = Pleroma.Config.get(:frontend_configurations, %{}) @@ -217,20 +225,16 @@ def frontend_configurations(conn, _params) do json(conn, config) end - def version(conn, _params) do + def version(%{assigns: %{format: "xml"}} = conn, _params) do version = Pleroma.Application.named_version() - case get_format(conn) do - "xml" -> - response = "#{version}" + conn + |> put_resp_content_type("application/xml") + |> send_resp(200, "#{version}") + end - conn - |> put_resp_content_type("application/xml") - |> send_resp(200, response) - - _ -> - json(conn, version) - end + def version(conn, _params) do + json(conn, Pleroma.Application.named_version()) end def emoji(conn, _params) do diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 2ed5f5042..d767ab9d4 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -51,6 +51,10 @@ def get("https://mastodon.social/users/emelie", _, _, _) do }} end + def get("https://mastodon.social/users/not_found", _, _, _) do + {:ok, %Tesla.Env{status: 404}} + end + def get("https://mastodon.sdf.org/users/rinpatch", _, _, _) do {:ok, %Tesla.Env{ diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 3d699e1df..640579c09 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -14,6 +14,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do setup do Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + + instance_config = Pleroma.Config.get([:instance]) + pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe]) + deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) + + on_exit(fn -> + Pleroma.Config.put([:instance], instance_config) + Pleroma.Config.put([:frontend_configurations, :pleroma_fe], pleroma_fe) + Pleroma.Config.put([:user, :deny_follow_blocked], deny_follow_blocked) + end) + :ok end @@ -31,6 +42,35 @@ test "it returns HTTP 200", %{conn: conn} do assert response == "job started" end + test "it imports follow lists from file", %{conn: conn} do + user1 = insert(:user) + user2 = insert(:user) + + with_mocks([ + {File, [], + read!: fn "follow_list.txt" -> + "Account address,Show boosts\n#{user2.ap_id},true" + end}, + {PleromaJobQueue, [:passthrough], []} + ]) do + response = + conn + |> assign(:user, user1) + |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}}) + |> json_response(:ok) + + assert called( + PleromaJobQueue.enqueue( + :background, + User, + [:follow_import, user1, [user2.ap_id]] + ) + ) + + assert response == "job started" + end + end + test "it imports new-style mastodon follow lists", %{conn: conn} do user1 = insert(:user) user2 = insert(:user) @@ -79,6 +119,33 @@ test "it returns HTTP 200", %{conn: conn} do assert response == "job started" end + + test "it imports blocks users from file", %{conn: conn} do + user1 = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + + with_mocks([ + {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}, + {PleromaJobQueue, [:passthrough], []} + ]) do + response = + conn + |> assign(:user, user1) + |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}}) + |> json_response(:ok) + + assert called( + PleromaJobQueue.enqueue( + :background, + User, + [:blocks_import, user1, [user2.ap_id, user3.ap_id]] + ) + ) + + assert response == "job started" + end + end end describe "POST /api/pleroma/notifications/read" do @@ -98,6 +165,18 @@ test "it marks a single notification as read", %{conn: conn} do assert Repo.get(Notification, notification1.id).seen refute Repo.get(Notification, notification2.id).seen end + + test "it returns error when notification not found", %{conn: conn} do + user1 = insert(:user) + + response = + conn + |> assign(:user, user1) + |> post("/api/pleroma/notifications/read", %{"id" => "22222222222222"}) + |> json_response(403) + + assert response == %{"error" => "Cannot get notification"} + end end describe "PUT /api/pleroma/notification_settings" do @@ -123,7 +202,63 @@ test "it updates notification settings", %{conn: conn} do end end - describe "GET /api/statusnet/config.json" do + describe "GET /api/statusnet/config" do + test "it returns config in xml format", %{conn: conn} do + instance = Pleroma.Config.get(:instance) + + response = + conn + |> put_req_header("accept", "application/xml") + |> get("/api/statusnet/config") + |> response(:ok) + + assert response == + "\n\n#{Keyword.get(instance, :name)}\n#{ + Pleroma.Web.base_url() + }\n#{Keyword.get(instance, :limit)}\n#{ + !Keyword.get(instance, :registrations_open) + }\n\n\n" + end + + test "it returns config in json format", %{conn: conn} do + instance = Pleroma.Config.get(:instance) + Pleroma.Config.put([:instance, :managed_config], true) + Pleroma.Config.put([:instance, :registrations_open], false) + Pleroma.Config.put([:instance, :invites_enabled], true) + Pleroma.Config.put([:instance, :public], false) + Pleroma.Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) + + response = + conn + |> put_req_header("accept", "application/json") + |> get("/api/statusnet/config") + |> json_response(:ok) + + expected_data = %{ + "site" => %{ + "accountActivationRequired" => "0", + "closed" => "1", + "description" => Keyword.get(instance, :description), + "invitesEnabled" => "1", + "name" => Keyword.get(instance, :name), + "pleromafe" => %{"theme" => "asuka-hospital"}, + "private" => "1", + "safeDMMentionsEnabled" => "0", + "server" => Pleroma.Web.base_url(), + "textlimit" => to_string(Keyword.get(instance, :limit)), + "uploadlimit" => %{ + "avatarlimit" => to_string(Keyword.get(instance, :avatar_upload_limit)), + "backgroundlimit" => to_string(Keyword.get(instance, :background_upload_limit)), + "bannerlimit" => to_string(Keyword.get(instance, :banner_upload_limit)), + "uploadlimit" => to_string(Keyword.get(instance, :upload_limit)) + }, + "vapidPublicKey" => Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key) + } + } + + assert response == expected_data + end + test "returns the state of safe_dm_mentions flag", %{conn: conn} do option = Pleroma.Config.get([:instance, :safe_dm_mentions]) Pleroma.Config.put([:instance, :safe_dm_mentions], true) @@ -210,7 +345,7 @@ test "returns json with custom emoji with tags", %{conn: conn} do end end - describe "GET /ostatus_subscribe?acct=...." do + describe "GET /ostatus_subscribe - remote_follow/2" do test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do conn = get( @@ -230,6 +365,172 @@ test "show follow account page if the `acct` is a account link", %{conn: conn} d assert html_response(response, 200) =~ "Log in to follow" end + + test "show follow page if the `acct` is a account link", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> get("/ostatus_subscribe?acct=https://mastodon.social/users/emelie") + + assert html_response(response, 200) =~ "Remote follow" + end + + test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found") + + assert html_response(response, 200) =~ "Error fetching user" + end + end + + describe "POST /ostatus_subscribe - do_remote_follow/2 with assigned user " do + test "follows user", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) + |> response(200) + + assert response =~ "Account followed!" + assert user2.follower_address in refresh_record(user).following + end + + test "returns error when user is deactivated", %{conn: conn} do + user = insert(:user, info: %{deactivated: true}) + user2 = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) + |> response(200) + + assert response =~ "Error following account" + end + + test "returns error when user is blocked", %{conn: conn} do + Pleroma.Config.put([:user, :deny_follow_blocked], true) + user = insert(:user) + user2 = insert(:user) + + {:ok, _user} = Pleroma.User.block(user2, user) + + response = + conn + |> assign(:user, user) + |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) + |> response(200) + + assert response =~ "Error following account" + end + + test "returns error when followee not found", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/ostatus_subscribe", %{"user" => %{"id" => "jimm"}}) + |> response(200) + + assert response =~ "Error following account" + end + + test "returns success result when user already in followers", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + {:ok, _, _, _} = CommonAPI.follow(user, user2) + + response = + conn + |> assign(:user, refresh_record(user)) + |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) + |> response(200) + + assert response =~ "Account followed!" + end + end + + describe "POST /ostatus_subscribe - do_remote_follow/2 without assigned user " do + test "follows", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + + response = + conn + |> post("/ostatus_subscribe", %{ + "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} + }) + |> response(200) + + assert response =~ "Account followed!" + assert user2.follower_address in refresh_record(user).following + end + + test "returns error when followee not found", %{conn: conn} do + user = insert(:user) + + response = + conn + |> post("/ostatus_subscribe", %{ + "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"} + }) + |> response(200) + + assert response =~ "Error following account" + end + + test "returns error when login invalid", %{conn: conn} do + user = insert(:user) + + response = + conn + |> post("/ostatus_subscribe", %{ + "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id} + }) + |> response(200) + + assert response =~ "Wrong username or password" + end + + test "returns error when password invalid", %{conn: conn} do + user = insert(:user) + user2 = insert(:user) + + response = + conn + |> post("/ostatus_subscribe", %{ + "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id} + }) + |> response(200) + + assert response =~ "Wrong username or password" + end + + test "returns error when user is blocked", %{conn: conn} do + Pleroma.Config.put([:user, :deny_follow_blocked], true) + user = insert(:user) + user2 = insert(:user) + {:ok, _user} = Pleroma.User.block(user2, user) + + response = + conn + |> post("/ostatus_subscribe", %{ + "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} + }) + |> response(200) + + assert response =~ "Error following account" + end end describe "GET /api/pleroma/healthcheck" do @@ -311,5 +612,104 @@ test "it returns HTTP 200", %{conn: conn} do assert user.info.deactivated == true end + + test "it returns returns when password invalid", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/api/pleroma/disable_account", %{"password" => "test1"}) + |> json_response(:ok) + + assert response == %{"error" => "Invalid password."} + user = User.get_cached_by_id(user.id) + + refute user.info.deactivated + end + end + + describe "GET /api/statusnet/version" do + test "it returns version in xml format", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/xml") + |> get("/api/statusnet/version") + |> response(:ok) + + assert response == "#{Pleroma.Application.named_version()}" + end + + test "it returns version in json format", %{conn: conn} do + response = + conn + |> put_req_header("accept", "application/json") + |> get("/api/statusnet/version") + |> json_response(:ok) + + assert response == "#{Pleroma.Application.named_version()}" + end + end + + describe "POST /main/ostatus - remote_subscribe/2" do + test "renders subscribe form", %{conn: conn} do + user = insert(:user) + + response = + conn + |> post("/main/ostatus", %{"nickname" => user.nickname, "profile" => ""}) + |> response(:ok) + + refute response =~ "Could not find user" + assert response =~ "Remotely follow #{user.nickname}" + end + + test "renders subscribe form with error when user not found", %{conn: conn} do + response = + conn + |> post("/main/ostatus", %{"nickname" => "nickname", "profile" => ""}) + |> response(:ok) + + assert response =~ "Could not find user" + refute response =~ "Remotely follow" + end + + test "it redirect to webfinger url", %{conn: conn} do + user = insert(:user) + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + conn = + conn + |> post("/main/ostatus", %{ + "user" => %{"nickname" => user.nickname, "profile" => user2.ap_id} + }) + + assert redirected_to(conn) == + "https://social.heldscal.la/main/ostatussub?profile=#{user.ap_id}" + end + + test "it renders form with error when use not found", %{conn: conn} do + user2 = insert(:user, ap_id: "shp@social.heldscal.la") + + response = + conn + |> post("/main/ostatus", %{"user" => %{"nickname" => "jimm", "profile" => user2.ap_id}}) + |> response(:ok) + + assert response =~ "Something went wrong." + end + end + + test "it returns new captcha", %{conn: conn} do + with_mock Pleroma.Captcha, + new: fn -> "test_captcha" end do + resp = + conn + |> get("/api/pleroma/captcha") + |> response(200) + + assert resp == "\"test_captcha\"" + assert called(Pleroma.Captcha.new()) + end end end From 301ea0dc0466371032f44f3e936d1b951ed9784c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 31 Jul 2019 19:37:55 +0300 Subject: [PATCH 062/202] Add tests for counters being updated on follow --- lib/pleroma/user.ex | 2 +- .../masto_closed_followers_page.json | 1 + .../masto_closed_following_page.json | 1 + test/support/http_request_mock.ex | 16 ++++ test/user_test.exs | 74 +++++++++++++++++++ test/web/activity_pub/activity_pub_test.exs | 20 ----- 6 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 test/fixtures/users_mock/masto_closed_followers_page.json create mode 100644 test/fixtures/users_mock/masto_closed_following_page.json diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7acf1e53c..69835f3dd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -741,7 +741,7 @@ def fetch_follow_information(user) do end def update_follower_count(%User{} = user) do - unless !user.local and Pleroma.Config.get([:instance, :external_user_synchronization]) do + if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do follower_count_query = User.Query.build(%{followers: user, deactivated: false}) |> select([u], %{count: count(u.id)}) diff --git a/test/fixtures/users_mock/masto_closed_followers_page.json b/test/fixtures/users_mock/masto_closed_followers_page.json new file mode 100644 index 000000000..04ab0c4d3 --- /dev/null +++ b/test/fixtures/users_mock/masto_closed_followers_page.json @@ -0,0 +1 @@ +{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/followers?page=1","type":"OrderedCollectionPage","totalItems":437,"next":"http://localhost:4001/users/masto_closed/followers?page=2","partOf":"http://localhost:4001/users/masto_closed/followers","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]} diff --git a/test/fixtures/users_mock/masto_closed_following_page.json b/test/fixtures/users_mock/masto_closed_following_page.json new file mode 100644 index 000000000..8d8324699 --- /dev/null +++ b/test/fixtures/users_mock/masto_closed_following_page.json @@ -0,0 +1 @@ +{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/following?page=1","type":"OrderedCollectionPage","totalItems":152,"next":"http://localhost:4001/users/masto_closed/following?page=2","partOf":"http://localhost:4001/users/masto_closed/following","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]} diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 2ed5f5042..bdfe43b28 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -792,6 +792,14 @@ def get("http://localhost:4001/users/masto_closed/followers", _, _, _) do }} end + def get("http://localhost:4001/users/masto_closed/followers?page=1", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json") + }} + end + def get("http://localhost:4001/users/masto_closed/following", _, _, _) do {:ok, %Tesla.Env{ @@ -800,6 +808,14 @@ def get("http://localhost:4001/users/masto_closed/following", _, _, _) do }} end + def get("http://localhost:4001/users/masto_closed/following?page=1", _, _, _) do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json") + }} + end + def get("http://localhost:4001/users/fuser2/followers", _, _, _) do {:ok, %Tesla.Env{ diff --git a/test/user_test.exs b/test/user_test.exs index 556df45fd..7ec241c25 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1393,4 +1393,78 @@ test "performs update cache if user updated" do assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id) end end + + describe "following/followers synchronization" do + setup do + sync = Pleroma.Config.get([:instance, :external_user_synchronization]) + on_exit(fn -> Pleroma.Config.put([:instance, :external_user_synchronization], sync) end) + end + + test "updates the counters normally on following/getting a follow when disabled" do + Pleroma.Config.put([:instance, :external_user_synchronization], false) + user = insert(:user) + + other_user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/masto_closed/followers", + following_address: "http://localhost:4001/users/masto_closed/following", + info: %{ap_enabled: true} + ) + + assert User.user_info(other_user).following_count == 0 + assert User.user_info(other_user).follower_count == 0 + + {:ok, user} = Pleroma.User.follow(user, other_user) + other_user = Pleroma.User.get_by_id(other_user.id) + + assert User.user_info(user).following_count == 1 + assert User.user_info(other_user).follower_count == 1 + end + + test "syncronizes the counters with the remote instance for the followed when enabled" do + Pleroma.Config.put([:instance, :external_user_synchronization], false) + + user = insert(:user) + + other_user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/masto_closed/followers", + following_address: "http://localhost:4001/users/masto_closed/following", + info: %{ap_enabled: true} + ) + + assert User.user_info(other_user).following_count == 0 + assert User.user_info(other_user).follower_count == 0 + + Pleroma.Config.put([:instance, :external_user_synchronization], true) + {:ok, _user} = User.follow(user, other_user) + other_user = User.get_by_id(other_user.id) + + assert User.user_info(other_user).follower_count == 437 + end + + test "syncronizes the counters with the remote instance for the follower when enabled" do + Pleroma.Config.put([:instance, :external_user_synchronization], false) + + user = insert(:user) + + other_user = + insert(:user, + local: false, + follower_address: "http://localhost:4001/users/masto_closed/followers", + following_address: "http://localhost:4001/users/masto_closed/following", + info: %{ap_enabled: true} + ) + + assert User.user_info(other_user).following_count == 0 + assert User.user_info(other_user).follower_count == 0 + + Pleroma.Config.put([:instance, :external_user_synchronization], true) + {:ok, other_user} = User.follow(other_user, user) + + assert User.user_info(other_user).following_count == 152 + end + end end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 853c93ab5..3d9a678dd 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1149,16 +1149,6 @@ test "detects hidden followers" do "http://localhost:4001/users/masto_closed/followers?page=1" -> %Tesla.Env{status: 403, body: ""} - "http://localhost:4001/users/masto_closed/following?page=1" -> - %Tesla.Env{ - status: 200, - body: - Jason.encode!(%{ - "id" => "http://localhost:4001/users/masto_closed/following?page=1", - "type" => "OrderedCollectionPage" - }) - } - _ -> apply(HttpRequestMock, :request, [env]) end @@ -1182,16 +1172,6 @@ test "detects hidden follows" do "http://localhost:4001/users/masto_closed/following?page=1" -> %Tesla.Env{status: 403, body: ""} - "http://localhost:4001/users/masto_closed/followers?page=1" -> - %Tesla.Env{ - status: 200, - body: - Jason.encode!(%{ - "id" => "http://localhost:4001/users/masto_closed/followers?page=1", - "type" => "OrderedCollectionPage" - }) - } - _ -> apply(HttpRequestMock, :request, [env]) end From f72e0b7caddd96da67269552db3102733e4a2581 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 31 Jul 2019 17:23:16 +0000 Subject: [PATCH 063/202] ostatus: explicitly disallow protocol downgrade from activitypub This closes embargoed bug #1135. --- CHANGELOG.md | 3 ++ .../web/ostatus/handlers/follow_handler.ex | 2 +- .../web/ostatus/handlers/note_handler.ex | 2 +- .../web/ostatus/handlers/unfollow_handler.ex | 2 +- lib/pleroma/web/ostatus/ostatus.ex | 17 +++++-- test/web/ostatus/ostatus_test.exs | 48 +++++++++++++++++-- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acd55362d..b02ed243b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Security +- OStatus: eliminate the possibility of a protocol downgrade attack. + ### Changed - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config - **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex index 263d3b2dc..03e4cbbb0 100644 --- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.OStatus.FollowHandler do alias Pleroma.Web.XML def handle(entry, doc) do - with {:ok, actor} <- OStatus.find_make_or_update_user(doc), + with {:ok, actor} <- OStatus.find_make_or_update_actor(doc), id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry), followed_uri when not is_nil(followed_uri) <- XML.string_from_xpath("/entry/activity:object/id", entry), diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex index 3005e8f57..7fae14f7b 100644 --- a/lib/pleroma/web/ostatus/handlers/note_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex @@ -111,7 +111,7 @@ def handle_note(entry, doc \\ nil, options \\ []) do with id <- XML.string_from_xpath("//id", entry), activity when is_nil(activity) <- Activity.get_create_by_object_ap_id_with_object(id), [author] <- :xmerl_xpath.string('//author[1]', doc), - {:ok, actor} <- OStatus.find_make_or_update_user(author), + {:ok, actor} <- OStatus.find_make_or_update_actor(author), content_html <- OStatus.get_content(entry), cw <- OStatus.get_cw(entry), in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry), diff --git a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex index 6596ada3b..2062432e3 100644 --- a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.OStatus.UnfollowHandler do alias Pleroma.Web.XML def handle(entry, doc) do - with {:ok, actor} <- OStatus.find_make_or_update_user(doc), + with {:ok, actor} <- OStatus.find_make_or_update_actor(doc), id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry), followed_uri when not is_nil(followed_uri) <- XML.string_from_xpath("/entry/activity:object/id", entry), diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 502410c83..331cbc0b7 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -56,7 +56,7 @@ def remote_follow_path do def handle_incoming(xml_string, options \\ []) do with doc when doc != :error <- parse_document(xml_string) do - with {:ok, actor_user} <- find_make_or_update_user(doc), + with {:ok, actor_user} <- find_make_or_update_actor(doc), do: Pleroma.Instances.set_reachable(actor_user.ap_id) entries = :xmerl_xpath.string('//entry', doc) @@ -120,7 +120,7 @@ def handle_incoming(xml_string, options \\ []) do end def make_share(entry, doc, retweeted_activity) do - with {:ok, actor} <- find_make_or_update_user(doc), + with {:ok, actor} <- find_make_or_update_actor(doc), %Object{} = object <- Object.normalize(retweeted_activity), id when not is_nil(id) <- string_from_xpath("/entry/id", entry), {:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do @@ -138,7 +138,7 @@ def handle_share(entry, doc) do end def make_favorite(entry, doc, favorited_activity) do - with {:ok, actor} <- find_make_or_update_user(doc), + with {:ok, actor} <- find_make_or_update_actor(doc), %Object{} = object <- Object.normalize(favorited_activity), id when not is_nil(id) <- string_from_xpath("/entry/id", entry), {:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do @@ -264,11 +264,18 @@ def maybe_update_ostatus(doc, user) do end end - def find_make_or_update_user(doc) do + def find_make_or_update_actor(doc) do uri = string_from_xpath("//author/uri[1]", doc) - with {:ok, user} <- find_or_make_user(uri) do + with {:ok, %User{} = user} <- find_or_make_user(uri), + {:ap_enabled, false} <- {:ap_enabled, User.ap_enabled?(user)} do maybe_update(doc, user) + else + {:ap_enabled, true} -> + {:error, :invalid_protocol} + + _ -> + {:error, :unknown_user} end end diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index 4e8f3a0fc..d244dbcf7 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -426,7 +426,7 @@ test "find_or_make_user sets all the nessary input fields" do } end - test "find_make_or_update_user takes an author element and returns an updated user" do + test "find_make_or_update_actor takes an author element and returns an updated user" do uri = "https://social.heldscal.la/user/23211" {:ok, user} = OStatus.find_or_make_user(uri) @@ -439,14 +439,56 @@ test "find_make_or_update_user takes an author element and returns an updated us doc = XML.parse_document(File.read!("test/fixtures/23211.atom")) [author] = :xmerl_xpath.string('//author[1]', doc) - {:ok, user} = OStatus.find_make_or_update_user(author) + {:ok, user} = OStatus.find_make_or_update_actor(author) assert user.avatar["type"] == "Image" assert user.name == old_name assert user.bio == old_bio - {:ok, user_again} = OStatus.find_make_or_update_user(author) + {:ok, user_again} = OStatus.find_make_or_update_actor(author) assert user_again == user end + + test "find_or_make_user disallows protocol downgrade" do + user = insert(:user, %{local: true}) + {:ok, user} = OStatus.find_or_make_user(user.ap_id) + + assert User.ap_enabled?(user) + + user = + insert(:user, %{ + ap_id: "https://social.heldscal.la/user/23211", + info: %{ap_enabled: true}, + local: false + }) + + assert User.ap_enabled?(user) + + {:ok, user} = OStatus.find_or_make_user(user.ap_id) + assert User.ap_enabled?(user) + end + + test "find_make_or_update_actor disallows protocol downgrade" do + user = insert(:user, %{local: true}) + {:ok, user} = OStatus.find_or_make_user(user.ap_id) + + assert User.ap_enabled?(user) + + user = + insert(:user, %{ + ap_id: "https://social.heldscal.la/user/23211", + info: %{ap_enabled: true}, + local: false + }) + + assert User.ap_enabled?(user) + + {:ok, user} = OStatus.find_or_make_user(user.ap_id) + assert User.ap_enabled?(user) + + doc = XML.parse_document(File.read!("test/fixtures/23211.atom")) + [author] = :xmerl_xpath.string('//author[1]', doc) + {:error, :invalid_protocol} = OStatus.find_make_or_update_actor(author) + end end describe "gathering user info from a user id" do From 6eb33e73035789fd9160e697617feb30a3070589 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 31 Jul 2019 18:35:15 +0000 Subject: [PATCH 064/202] test for Pleroma.Web.CommonAPI.Utils.get_by_id_or_ap_id --- lib/pleroma/flake_id.ex | 10 ++++++++++ lib/pleroma/web/common_api/utils.ex | 7 ++++++- test/flake_id_test.exs | 5 +++++ test/web/common_api/common_api_utils_test.exs | 20 +++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex index 58ab3650d..ca0610abc 100644 --- a/lib/pleroma/flake_id.ex +++ b/lib/pleroma/flake_id.ex @@ -66,6 +66,16 @@ def from_integer(integer) do @spec get :: binary def get, do: to_string(:gen_server.call(:flake, :get)) + # checks that ID is is valid FlakeID + # + @spec is_flake_id?(String.t()) :: boolean + def is_flake_id?(id), do: is_flake_id?(String.to_charlist(id), true) + defp is_flake_id?([c | cs], true) when c >= ?0 and c <= ?9, do: is_flake_id?(cs, true) + defp is_flake_id?([c | cs], true) when c >= ?A and c <= ?Z, do: is_flake_id?(cs, true) + defp is_flake_id?([c | cs], true) when c >= ?a and c <= ?z, do: is_flake_id?(cs, true) + defp is_flake_id?([], true), do: true + defp is_flake_id?(_, _), do: false + # -- Ecto.Type API @impl Ecto.Type def type, do: :uuid diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index d80fffa26..c8a743e8e 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -24,7 +24,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do # This is a hack for twidere. def get_by_id_or_ap_id(id) do activity = - Activity.get_by_id_with_object(id) || Activity.get_create_by_object_ap_id_with_object(id) + with true <- Pleroma.FlakeId.is_flake_id?(id), + %Activity{} = activity <- Activity.get_by_id_with_object(id) do + activity + else + _ -> Activity.get_create_by_object_ap_id_with_object(id) + end activity && if activity.data["type"] == "Create" do diff --git a/test/flake_id_test.exs b/test/flake_id_test.exs index ca2338041..85ed5bbdf 100644 --- a/test/flake_id_test.exs +++ b/test/flake_id_test.exs @@ -39,4 +39,9 @@ test "ecto type behaviour" do assert dump(flake_s) == {:ok, flake} assert dump(flake) == {:ok, flake} end + + test "is_flake_id?/1" do + assert is_flake_id?("9eoozpwTul5mjSEDRI") + refute is_flake_id?("http://example.com/activities/3ebbadd1-eb14-4e20-8118-b6f79c0c7b0b") + end end diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index af320f31f..4b5666c29 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -360,4 +360,24 @@ test "for direct posts, a reply" do assert third_user.ap_id in to end end + + describe "get_by_id_or_ap_id/1" do + test "get activity by id" do + activity = insert(:note_activity) + %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.id) + assert note.id == activity.id + end + + test "get activity by ap_id" do + activity = insert(:note_activity) + %Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.data["object"]) + assert note.id == activity.id + end + + test "get activity by object when type isn't `Create` " do + activity = insert(:like_activity) + %Pleroma.Activity{} = like = Utils.get_by_id_or_ap_id(activity.id) + assert like.data["object"] == activity.data["object"] + end + end end From 813c686dd77e6d441c235b2f7a57ac7911e249af Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 31 Jul 2019 22:05:12 +0300 Subject: [PATCH 065/202] Disallow following locked accounts over OStatus --- lib/pleroma/web/ostatus/handlers/follow_handler.ex | 4 ++++ test/web/ostatus/ostatus_test.exs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex index 03e4cbbb0..24513972e 100644 --- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex @@ -14,9 +14,13 @@ def handle(entry, doc) do followed_uri when not is_nil(followed_uri) <- XML.string_from_xpath("/entry/activity:object/id", entry), {:ok, followed} <- OStatus.find_or_make_user(followed_uri), + {:locked, false} <- {:locked, followed.info.locked}, {:ok, activity} <- ActivityPub.follow(actor, followed, id, false) do User.follow(actor, followed) {:ok, activity} + else + {:locked, true} -> + {:error, "It's not possible to follow locked accounts over OStatus"} end end end diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index d244dbcf7..f8d389020 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -326,6 +326,14 @@ test "handle incoming follows" do assert User.following?(follower, followed) end + test "refuse following over OStatus if the followed's account is locked" do + incoming = File.read!("test/fixtures/follow.xml") + _user = insert(:user, info: %{locked: true}, ap_id: "https://pawoo.net/users/pekorino") + + {:ok, [{:error, "It's not possible to follow locked accounts over OStatus"}]} = + OStatus.handle_incoming(incoming) + end + test "handle incoming unfollows with existing follow" do incoming_follow = File.read!("test/fixtures/follow.xml") {:ok, [_activity]} = OStatus.handle_incoming(incoming_follow) From def0c49ead94d21a63bdc7323521b6d73ad4c0b2 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 31 Jul 2019 23:03:06 +0300 Subject: [PATCH 066/202] Add a changelog entry for disallowing locked accounts follows over OStatus --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b02ed243b..bd64b2259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] ### Security - OStatus: eliminate the possibility of a protocol downgrade attack. +- OStatus: prevent following locked accounts, bypassing the approval process. ### Changed - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config From 9ca45063556f3b75860d516577776a00536e90a8 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 1 Aug 2019 15:53:37 +0700 Subject: [PATCH 067/202] Add configurable length limits for `User.bio` and `User.name` --- config/config.exs | 2 ++ docs/config.md | 2 ++ lib/pleroma/user.ex | 38 +++++++++++++++++++++----------------- test/user_test.exs | 5 ++++- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/config/config.exs b/config/config.exs index 17770640a..aa4cdf409 100644 --- a/config/config.exs +++ b/config/config.exs @@ -253,6 +253,8 @@ skip_thread_containment: true, limit_to_local_content: :unauthenticated, dynamic_configuration: false, + user_bio_length: 5000, + user_name_length: 100, external_user_synchronization: true config :pleroma, :markup, diff --git a/docs/config.md b/docs/config.md index 02f86dc16..8f58eaf06 100644 --- a/docs/config.md +++ b/docs/config.md @@ -125,6 +125,8 @@ config :pleroma, Pleroma.Emails.Mailer, * `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`. * `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``. * `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database. +* `user_bio_length`: A user bio maximum length (default: `5000`) +* `user_name_length`: A user name maximum length (default: `100`) * `skip_thread_containment`: Skip filter out broken threads. The default is `false`. * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1adb82f32..776dbbe6d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -149,10 +149,10 @@ def following_count(%User{} = user) do end def remote_user_creation(params) do - params = - params - |> Map.put(:info, params[:info] || %{}) + bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) + name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + params = Map.put(params, :info, params[:info] || %{}) info_cng = User.Info.remote_user_creation(%User.Info{}, params[:info]) changes = @@ -161,8 +161,8 @@ def remote_user_creation(params) do |> validate_required([:name, :ap_id]) |> unique_constraint(:nickname) |> validate_format(:nickname, @email_regex) - |> validate_length(:bio, max: 5000) - |> validate_length(:name, max: 100) + |> validate_length(:bio, max: bio_limit) + |> validate_length(:name, max: name_limit) |> put_change(:local, false) |> put_embed(:info, info_cng) @@ -185,22 +185,23 @@ def remote_user_creation(params) do end def update_changeset(struct, params \\ %{}) do + bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) + name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + struct |> cast(params, [:bio, :name, :avatar, :following]) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) - |> validate_length(:bio, max: 5000) - |> validate_length(:name, min: 1, max: 100) + |> validate_length(:bio, max: bio_limit) + |> validate_length(:name, min: 1, max: name_limit) end def upgrade_changeset(struct, params \\ %{}) do - params = - params - |> Map.put(:last_refreshed_at, NaiveDateTime.utc_now()) + bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) + name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) - info_cng = - struct.info - |> User.Info.user_upgrade(params[:info]) + params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now()) + info_cng = User.Info.user_upgrade(struct.info, params[:info]) struct |> cast(params, [ @@ -213,8 +214,8 @@ def upgrade_changeset(struct, params \\ %{}) do ]) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) - |> validate_length(:bio, max: 5000) - |> validate_length(:name, max: 100) + |> validate_length(:bio, max: bio_limit) + |> validate_length(:name, max: name_limit) |> put_embed(:info, info_cng) end @@ -241,6 +242,9 @@ def reset_password(%User{id: user_id} = user, data) do end def register_changeset(struct, params \\ %{}, opts \\ []) do + bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) + name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + need_confirmation? = if is_nil(opts[:need_confirmation]) do Pleroma.Config.get([:instance, :account_activation_required]) @@ -261,8 +265,8 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do |> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames])) |> validate_format(:nickname, local_nickname_regex()) |> validate_format(:email, @email_regex) - |> validate_length(:bio, max: 1000) - |> validate_length(:name, min: 1, max: 100) + |> validate_length(:bio, max: bio_limit) + |> validate_length(:name, min: 1, max: name_limit) |> put_change(:info, info_change) changeset = diff --git a/test/user_test.exs b/test/user_test.exs index 556df45fd..dfa91a106 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -525,7 +525,10 @@ test "it has required fields" do end test "it restricts some sizes" do - [bio: 5000, name: 100] + bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) + name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + + [bio: bio_limit, name: name_limit] |> Enum.each(fn {field, size} -> string = String.pad_leading(".", size) cs = User.remote_user_creation(Map.put(@valid_remote, field, string)) From f98235f2adfff290d95c7353c63225c07e5f86ff Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 1 Aug 2019 16:33:36 +0700 Subject: [PATCH 068/202] Clean up tests output --- test/web/admin_api/admin_api_controller_test.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 824ad23e6..f61499a22 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1922,7 +1922,10 @@ test "queues key as atom", %{conn: conn} do temp_file = "config/test.exported_from_db.secret.exs" + Mix.shell(Mix.Shell.Quiet) + on_exit(fn -> + Mix.shell(Mix.Shell.IO) :ok = File.rm(temp_file) end) From 81412240e6e6ca60a7fcece5eff056722d868d2e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 1 Aug 2019 14:15:18 +0300 Subject: [PATCH 069/202] Fix Invalid SemVer version generation when the current branch does not have commits ahead of tag/checked out on a tag --- CHANGELOG.md | 1 + mix.exs | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd64b2259..6fdc432ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification. - ActivityPub S2S: remote user deletions now work the same as local user deletions. - Not being able to access the Mastodon FE login page on private instances +- Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) diff --git a/mix.exs b/mix.exs index 2a8fe2e9d..dfff53d57 100644 --- a/mix.exs +++ b/mix.exs @@ -190,12 +190,13 @@ defp version(version) do tag = String.trim(tag), {describe, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=8"]), describe = String.trim(describe), - ahead <- String.replace(describe, tag, "") do + ahead <- String.replace(describe, tag, ""), + ahead <- String.trim_leading(ahead, "-") do {String.replace_prefix(tag, "v", ""), if(ahead != "", do: String.trim(ahead))} else _ -> {commit_hash, 0} = System.cmd("git", ["rev-parse", "--short", "HEAD"]) - {nil, "-0-g" <> String.trim(commit_hash)} + {nil, "0-g" <> String.trim(commit_hash)} end if git_tag && version != git_tag do @@ -207,14 +208,15 @@ defp version(version) do # Branch name as pre-release version component, denoted with a dot branch_name = with {branch_name, 0} <- System.cmd("git", ["rev-parse", "--abbrev-ref", "HEAD"]), + branch_name <- String.trim(branch_name), branch_name <- System.get_env("PLEROMA_BUILD_BRANCH") || branch_name, - true <- branch_name != "master" do + true <- branch_name not in ["master", "HEAD"] do branch_name = branch_name |> String.trim() |> String.replace(identifier_filter, "-") - "." <> branch_name + branch_name end build_name = @@ -234,6 +236,17 @@ defp version(version) do env_override -> env_override end + # Pre-release version, denoted by appending a hyphen + # and a series of dot separated identifiers + pre_release = + [git_pre_release, branch_name] + |> Enum.filter(fn string -> string && string != "" end) + |> Enum.join(".") + |> (fn + "" -> nil + string -> "-" <> String.replace(string, identifier_filter, "-") + end).() + # Build metadata, denoted with a plus sign build_metadata = [build_name, env_name] @@ -244,7 +257,7 @@ defp version(version) do string -> "+" <> String.replace(string, identifier_filter, "-") end).() - [version, git_pre_release, branch_name, build_metadata] + [version, pre_release, build_metadata] |> Enum.filter(fn string -> string && string != "" end) |> Enum.join() end From fd4b7239cd6f44a25c9aa4195750e94e0612a3b1 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 1 Aug 2019 17:25:46 +0200 Subject: [PATCH 070/202] nothing From f88560accd801ac88c60344cef93ef00cf136069 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 2 Aug 2019 11:55:41 +0200 Subject: [PATCH 071/202] Conversations: Add recipient list to conversation participation. This enables to address the same group of people every time. --- lib/pleroma/conversation.ex | 11 ++++++ lib/pleroma/conversation/participation.ex | 4 +++ .../participation_recipient_ship.ex | 34 +++++++++++++++++++ lib/pleroma/user.ex | 7 ++++ .../20190205114625_create_thread_mutes.exs | 2 +- ...ersation_participation_recipient_ships.exs | 13 +++++++ test/conversation/participation_test.exs | 30 ++++++++++++++++ 7 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/conversation/participation_recipient_ship.ex create mode 100644 priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index bc97b39ca..fb0dfedca 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Conversation do alias Pleroma.Conversation.Participation + alias Pleroma.Conversation.Participation.RecipientShip alias Pleroma.Repo alias Pleroma.User use Ecto.Schema @@ -39,6 +40,15 @@ def get_for_ap_id(ap_id) do Repo.get_by(__MODULE__, ap_id: ap_id) end + def maybe_set_recipients(participation, activity) do + participation = Repo.preload(participation, :recipients) + + if participation.recipients |> Enum.empty?() do + recipients = User.get_all_by_ap_id(activity.recipients) + RecipientShip.create(recipients, participation) + end + end + @doc """ This will 1. Create a conversation if there isn't one already @@ -60,6 +70,7 @@ def create_or_bump_for(activity, opts \\ []) do {:ok, participation} = Participation.create_for_user_and_conversation(user, conversation, opts) + maybe_set_recipients(participation, activity) participation end) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 77b3f61e9..121efb671 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Conversation.Participation do use Ecto.Schema alias Pleroma.Conversation + alias Pleroma.Conversation.Participation.RecipientShip alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -17,6 +18,9 @@ defmodule Pleroma.Conversation.Participation do field(:read, :boolean, default: false) field(:last_activity_id, Pleroma.FlakeId, virtual: true) + has_many(:recipient_ships, RecipientShip) + has_many(:recipients, through: [:recipient_ships, :user]) + timestamps() end diff --git a/lib/pleroma/conversation/participation_recipient_ship.ex b/lib/pleroma/conversation/participation_recipient_ship.ex new file mode 100644 index 000000000..27c0c89cd --- /dev/null +++ b/lib/pleroma/conversation/participation_recipient_ship.ex @@ -0,0 +1,34 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Conversation.Participation.RecipientShip do + use Ecto.Schema + + alias Pleroma.Conversation.Participation + alias Pleroma.User + alias Pleroma.Repo + + import Ecto.Changeset + + schema "conversation_participation_recipient_ships" do + belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:participation, Participation) + end + + def creation_cng(struct, params) do + struct + |> cast(params, [:user_id, :participation_id]) + |> validate_required([:user_id, :participation_id]) + end + + def create(%User{} = user, participation), do: create([user], participation) + + def create(users, participation) do + Enum.each(users, fn user -> + %__MODULE__{} + |> creation_cng(%{user_id: user.id, participation_id: participation.id}) + |> Repo.insert!() + end) + end +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6e2fd3af8..a021e77f0 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -450,6 +450,13 @@ def get_by_ap_id(ap_id) do Repo.get_by(User, ap_id: ap_id) end + def get_all_by_ap_id(ap_ids) do + from(u in __MODULE__, + where: u.ap_id in ^ap_ids + ) + |> Repo.all() + end + # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part # of the ap_id and the domain and tries to get that user def get_by_guessed_nickname(ap_id) do diff --git a/priv/repo/migrations/20190205114625_create_thread_mutes.exs b/priv/repo/migrations/20190205114625_create_thread_mutes.exs index 7e44db121..baaf07253 100644 --- a/priv/repo/migrations/20190205114625_create_thread_mutes.exs +++ b/priv/repo/migrations/20190205114625_create_thread_mutes.exs @@ -6,7 +6,7 @@ def change do add :user_id, references(:users, type: :uuid, on_delete: :delete_all) add :context, :string end - + create_if_not_exists unique_index(:thread_mutes, [:user_id, :context], name: :unique_index) end end diff --git a/priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs b/priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs new file mode 100644 index 000000000..c6e3469d5 --- /dev/null +++ b/priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs @@ -0,0 +1,13 @@ +defmodule Pleroma.Repo.Migrations.CreateConversationParticipationRecipientShips do + use Ecto.Migration + + def change do + create_if_not_exists table(:conversation_participation_recipient_ships) do + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:participation_id, references(:conversation_participations, on_delete: :delete_all)) + end + + create_if_not_exists index(:conversation_participation_recipient_ships, [:user_id]) + create_if_not_exists index(:conversation_participation_recipient_ships, [:participation_id]) + end +end diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 2a03e5d67..4a3c397bd 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -8,6 +8,36 @@ defmodule Pleroma.Conversation.ParticipationTest do alias Pleroma.Conversation.Participation alias Pleroma.Web.CommonAPI + test "for a new conversation, it sets the recipents of the participation" do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"}) + + [participation] = Participation.for_user(user) + participation = Pleroma.Repo.preload(participation, :recipients) + + assert length(participation.recipients) == 2 + assert user in participation.recipients + assert other_user in participation.recipients + + # Mentioning another user in the same conversation will not add a new recipients. + + {:ok, _activity} = + CommonAPI.post(user, %{ + "in_reply_to_status_id" => activity.id, + "status" => "Hey @#{third_user.nickname}.", + "visibility" => "direct" + }) + + [participation] = Participation.for_user(user) + participation = Pleroma.Repo.preload(participation, :recipients) + + assert length(participation.recipients) == 2 + end + test "it creates a participation for a conversation and a user" do user = insert(:user) conversation = insert(:conversation) From 56b1c3af13c9519e13da688bdbbfdd8d69cda4ac Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 2 Aug 2019 15:05:27 +0200 Subject: [PATCH 072/202] CommonAPI: Extend api with conversation replies. --- lib/pleroma/conversation/participation.ex | 6 +++++ lib/pleroma/web/common_api/common_api.ex | 20 ++++++++++----- lib/pleroma/web/common_api/utils.ex | 27 ++++++++++++++------ test/web/common_api/common_api_test.exs | 30 +++++++++++++++++++++++ 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 121efb671..f1e1a6958 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -93,4 +93,10 @@ def for_user_with_last_activity_id(user, params \\ %{}) do end) |> Enum.filter(& &1.last_activity_id) end + + def get(nil), do: nil + + def get(id) do + Repo.get(__MODULE__, id) + end end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2db58324b..86e95cd0f 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.CommonAPI do alias Pleroma.Activity + alias Pleroma.Conversation.Participation alias Pleroma.Formatter alias Pleroma.Object alias Pleroma.ThreadMute @@ -171,21 +172,25 @@ defp normalize_and_validate_choice_indices(choices, count) do end) end - def get_visibility(%{"visibility" => visibility}, in_reply_to) + def get_visibility(_, _, %Participation{}) do + {"direct", "direct"} + end + + def get_visibility(%{"visibility" => visibility}, in_reply_to, _) when visibility in ~w{public unlisted private direct}, do: {visibility, get_replied_to_visibility(in_reply_to)} - def get_visibility(%{"visibility" => "list:" <> list_id}, in_reply_to) do + def get_visibility(%{"visibility" => "list:" <> list_id}, in_reply_to, _) do visibility = {:list, String.to_integer(list_id)} {visibility, get_replied_to_visibility(in_reply_to)} end - def get_visibility(_, in_reply_to) when not is_nil(in_reply_to) do + def get_visibility(_, in_reply_to, _) when not is_nil(in_reply_to) do visibility = get_replied_to_visibility(in_reply_to) {visibility, visibility} end - def get_visibility(_, in_reply_to), do: {"public", get_replied_to_visibility(in_reply_to)} + def get_visibility(_, in_reply_to, _), do: {"public", get_replied_to_visibility(in_reply_to)} def get_replied_to_visibility(nil), do: nil @@ -201,7 +206,9 @@ def post(user, %{"status" => status} = data) do with status <- String.trim(status), attachments <- attachments_from_ids(data), in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]), - {visibility, in_reply_to_visibility} <- get_visibility(data, in_reply_to), + in_reply_to_conversation <- Participation.get(data["in_reply_to_conversation_id"]), + {visibility, in_reply_to_visibility} <- + get_visibility(data, in_reply_to, in_reply_to_conversation), {_, false} <- {:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"}, {content_html, mentions, tags} <- @@ -214,7 +221,8 @@ def post(user, %{"status" => status} = data) do mentioned_users <- for({_, mentioned_user} <- mentions, do: mentioned_user.ap_id), addressed_users <- get_addressed_users(mentioned_users, data["to"]), {poll, poll_emoji} <- make_poll_data(data), - {to, cc} <- get_to_and_cc(user, addressed_users, in_reply_to, visibility), + {to, cc} <- + get_to_and_cc(user, addressed_users, in_reply_to, visibility, in_reply_to_conversation), context <- make_context(in_reply_to), cw <- data["spoiler_text"] || "", sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}), diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index d80fffa26..e70ba7d43 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do alias Calendar.Strftime alias Pleroma.Activity alias Pleroma.Config + alias Pleroma.Conversation.Participation alias Pleroma.Formatter alias Pleroma.Object alias Pleroma.Plugs.AuthenticationPlug @@ -64,9 +65,21 @@ def attachments_from_ids_descs(ids, descs_str) do end) end - @spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) :: + @spec get_to_and_cc( + User.t(), + list(String.t()), + Activity.t() | nil, + String.t(), + Participation.t() | nil + ) :: {list(String.t()), list(String.t())} - def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do + + def get_to_and_cc(_, _, _, _, %Participation{} = participation) do + participation = Repo.preload(participation, :recipients) + {Enum.map(participation.recipients, & &1.ap_id), []} + end + + def get_to_and_cc(user, mentioned_users, inReplyTo, "public", _) do to = [Pleroma.Constants.as_public() | mentioned_users] cc = [user.follower_address] @@ -77,7 +90,7 @@ def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do end end - def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do + def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted", _) do to = [user.follower_address | mentioned_users] cc = [Pleroma.Constants.as_public()] @@ -88,12 +101,12 @@ def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do end end - def get_to_and_cc(user, mentioned_users, inReplyTo, "private") do - {to, cc} = get_to_and_cc(user, mentioned_users, inReplyTo, "direct") + def get_to_and_cc(user, mentioned_users, inReplyTo, "private", _) do + {to, cc} = get_to_and_cc(user, mentioned_users, inReplyTo, "direct", nil) {[user.follower_address | to], cc} end - def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct") do + def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct", _) do if inReplyTo do {Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []} else @@ -101,7 +114,7 @@ def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct") do end end - def get_to_and_cc(_user, mentions, _inReplyTo, {:list, _}), do: {mentions, []} + def get_to_and_cc(_user, mentions, _inReplyTo, {:list, _}, _), do: {mentions, []} def get_addressed_users(_, to) when is_list(to) do User.get_ap_ids_by_nicknames(to) diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 16b3f121d..e2a5bf117 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.CommonAPITest do use Pleroma.DataCase alias Pleroma.Activity + alias Pleroma.Conversation.Participation alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -12,6 +13,35 @@ defmodule Pleroma.Web.CommonAPITest do import Pleroma.Factory + test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do + har = insert(:user) + jafnhar = insert(:user) + tridi = insert(:user) + + {:ok, activity} = + CommonAPI.post(har, %{ + "status" => "@#{jafnhar.nickname} hey", + "visibility" => "direct" + }) + + assert har.ap_id in activity.recipients + assert jafnhar.ap_id in activity.recipients + + [participation] = Participation.for_user(har) + + {:ok, activity} = + CommonAPI.post(har, %{ + "status" => "I don't really like @#{tridi.nickname}", + "visibility" => "direct", + "in_reply_to_status_id" => activity.id, + "in_reply_to_conversation_id" => participation.id + }) + + assert har.ap_id in activity.recipients + assert jafnhar.ap_id in activity.recipients + refute tridi.ap_id in activity.recipients + end + test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do har = insert(:user) jafnhar = insert(:user) From d93d7779151c811e991e99098e64c1da2c783d68 Mon Sep 17 00:00:00 2001 From: feld Date: Fri, 2 Aug 2019 17:07:09 +0000 Subject: [PATCH 073/202] Fix/mediaproxy whitelist base url --- CHANGELOG.md | 1 + lib/pleroma/web/media_proxy/media_proxy.ex | 14 ++++- .../mastodon_api_controller_test.exs | 34 ----------- test/web/media_proxy/media_proxy_test.exs | 58 ++++++++++++------- 4 files changed, 51 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fdc432ef..4fa9ffd9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ActivityPub S2S: remote user deletions now work the same as local user deletions. - Not being able to access the Mastodon FE login page on private instances - Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag +- Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex index a661e9bb7..1725ab071 100644 --- a/lib/pleroma/web/media_proxy/media_proxy.ex +++ b/lib/pleroma/web/media_proxy/media_proxy.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.MediaProxy do alias Pleroma.Config + alias Pleroma.Upload alias Pleroma.Web @base64_opts [padding: false] @@ -26,7 +27,18 @@ defp local?(url), do: String.starts_with?(url, Pleroma.Web.base_url()) defp whitelisted?(url) do %{host: domain} = URI.parse(url) - Enum.any?(Config.get([:media_proxy, :whitelist]), fn pattern -> + mediaproxy_whitelist = Config.get([:media_proxy, :whitelist]) + + upload_base_url_domain = + if !is_nil(Config.get([Upload, :base_url])) do + [URI.parse(Config.get([Upload, :base_url])).host] + else + [] + end + + whitelist = mediaproxy_whitelist ++ upload_base_url_domain + + Enum.any?(whitelist, fn pattern -> String.equivalent?(domain, pattern) end) end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 66016c886..e49c4cc22 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1671,40 +1671,6 @@ test "returns uploaded image", %{conn: conn, image: image} do object = Repo.get(Object, media["id"]) assert object.data["actor"] == User.ap_id(conn.assigns[:user]) end - - test "returns proxied url when media proxy is enabled", %{conn: conn, image: image} do - Pleroma.Config.put([Pleroma.Upload, :base_url], "https://media.pleroma.social") - - proxy_url = "https://cache.pleroma.social" - Pleroma.Config.put([:media_proxy, :enabled], true) - Pleroma.Config.put([:media_proxy, :base_url], proxy_url) - - media = - conn - |> post("/api/v1/media", %{"file" => image}) - |> json_response(:ok) - - assert String.starts_with?(media["url"], proxy_url) - end - - test "returns media url when proxy is enabled but media url is whitelisted", %{ - conn: conn, - image: image - } do - media_url = "https://media.pleroma.social" - Pleroma.Config.put([Pleroma.Upload, :base_url], media_url) - - Pleroma.Config.put([:media_proxy, :enabled], true) - Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social") - Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"]) - - media = - conn - |> post("/api/v1/media", %{"file" => image}) - |> json_response(:ok) - - assert String.starts_with?(media["url"], media_url) - end end describe "locked accounts" do diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs index edbbf9b66..0c94755df 100644 --- a/test/web/media_proxy/media_proxy_test.exs +++ b/test/web/media_proxy/media_proxy_test.exs @@ -171,21 +171,6 @@ test "preserve unicode characters" do encoded = url(url) assert decode_result(encoded) == url end - - test "does not change whitelisted urls" do - upload_config = Pleroma.Config.get([Pleroma.Upload]) - media_url = "https://media.pleroma.social" - Pleroma.Config.put([Pleroma.Upload, :base_url], media_url) - Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"]) - Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social") - - url = "#{media_url}/static/logo.png" - encoded = url(url) - - assert String.starts_with?(encoded, media_url) - - Pleroma.Config.put([Pleroma.Upload], upload_config) - end end describe "when disabled" do @@ -215,12 +200,43 @@ defp decode_result(encoded) do decoded end - test "mediaproxy whitelist" do - Pleroma.Config.put([:media_proxy, :enabled], true) - Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"]) - url = "https://feld.me/foo.png" + describe "whitelist" do + setup do + Pleroma.Config.put([:media_proxy, :enabled], true) + :ok + end - unencoded = url(url) - assert unencoded == url + test "mediaproxy whitelist" do + Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"]) + url = "https://feld.me/foo.png" + + unencoded = url(url) + assert unencoded == url + end + + test "does not change whitelisted urls" do + Pleroma.Config.put([:media_proxy, :whitelist], ["mycdn.akamai.com"]) + Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social") + + media_url = "https://mycdn.akamai.com" + + url = "#{media_url}/static/logo.png" + encoded = url(url) + + assert String.starts_with?(encoded, media_url) + end + + test "ensure Pleroma.Upload base_url is always whitelisted" do + upload_config = Pleroma.Config.get([Pleroma.Upload]) + media_url = "https://media.pleroma.social" + Pleroma.Config.put([Pleroma.Upload, :base_url], media_url) + + url = "#{media_url}/static/logo.png" + encoded = url(url) + + assert String.starts_with?(encoded, media_url) + + Pleroma.Config.put([Pleroma.Upload], upload_config) + end end end From eee98aaa738c1aa5f2e4203a61b67648d62965c8 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 2 Aug 2019 19:53:08 +0200 Subject: [PATCH 074/202] Pleroma API: Add endpoint to get conversation statuses. --- lib/pleroma/web/controller_helper.ex | 76 +++++++++++++++++++ .../mastodon_api/mastodon_api_controller.ex | 68 +---------------- .../web/pleroma_api/pleroma_api_controller.ex | 49 ++++++++++++ lib/pleroma/web/router.ex | 9 +++ test/web/common_api/common_api_utils_test.exs | 16 ++-- .../pleroma_api_controller_test.exs | 45 +++++++++++ 6 files changed, 189 insertions(+), 74 deletions(-) create mode 100644 lib/pleroma/web/pleroma_api/pleroma_api_controller.ex create mode 100644 test/web/pleroma_api/pleroma_api_controller_test.exs diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 8a753bb4f..eeac9f503 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -33,4 +33,80 @@ defp param_to_integer(val, default) when is_binary(val) do end defp param_to_integer(_, default), do: default + + def add_link_headers( + conn, + method, + activities, + param \\ nil, + params \\ %{}, + func3 \\ nil, + func4 \\ nil + ) do + params = + conn.params + |> Map.drop(["since_id", "max_id", "min_id"]) + |> Map.merge(params) + + last = List.last(activities) + + func3 = func3 || (&mastodon_api_url/3) + func4 = func4 || (&mastodon_api_url/4) + + if last do + max_id = last.id + + limit = + params + |> Map.get("limit", "20") + |> String.to_integer() + + min_id = + if length(activities) <= limit do + activities + |> List.first() + |> Map.get(:id) + else + activities + |> Enum.at(limit * -1) + |> Map.get(:id) + end + + {next_url, prev_url} = + if param do + { + func4.( + Pleroma.Web.Endpoint, + method, + param, + Map.merge(params, %{max_id: max_id}) + ), + func4.( + Pleroma.Web.Endpoint, + method, + param, + Map.merge(params, %{min_id: min_id}) + ) + } + else + { + func3.( + Pleroma.Web.Endpoint, + method, + Map.merge(params, %{max_id: max_id}) + ), + func3.( + Pleroma.Web.Endpoint, + method, + Map.merge(params, %{min_id: min_id}) + ) + } + end + + conn + |> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"") + else + conn + end + 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 174e93468..0deeab2be 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -5,7 +5,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller - import Pleroma.Web.ControllerHelper, only: [json_response: 3] + import Pleroma.Web.ControllerHelper, + only: [json_response: 3, add_link_headers: 5, add_link_headers: 4, add_link_headers: 3] alias Ecto.Changeset alias Pleroma.Activity @@ -342,71 +343,6 @@ def custom_emojis(conn, _params) do json(conn, mastodon_emoji) end - defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do - params = - conn.params - |> Map.drop(["since_id", "max_id", "min_id"]) - |> Map.merge(params) - - last = List.last(activities) - - if last do - max_id = last.id - - limit = - params - |> Map.get("limit", "20") - |> String.to_integer() - - min_id = - if length(activities) <= limit do - activities - |> List.first() - |> Map.get(:id) - else - activities - |> Enum.at(limit * -1) - |> Map.get(:id) - end - - {next_url, prev_url} = - if param do - { - mastodon_api_url( - Pleroma.Web.Endpoint, - method, - param, - Map.merge(params, %{max_id: max_id}) - ), - mastodon_api_url( - Pleroma.Web.Endpoint, - method, - param, - Map.merge(params, %{min_id: min_id}) - ) - } - else - { - mastodon_api_url( - Pleroma.Web.Endpoint, - method, - Map.merge(params, %{max_id: max_id}) - ), - mastodon_api_url( - Pleroma.Web.Endpoint, - method, - Map.merge(params, %{min_id: min_id}) - ) - } - end - - conn - |> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"") - else - conn - end - end - def home_timeline(%{assigns: %{user: user}} = conn, params) do params = params diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex new file mode 100644 index 000000000..b677892ed --- /dev/null +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do + use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] + + alias Pleroma.Conversation.Participation + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Repo + + def conversation_statuses( + %{assigns: %{user: user}} = conn, + %{"id" => participation_id} = params + ) do + params = + params + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + + participation = + participation_id + |> Participation.get() + |> Repo.preload(:conversation) + + if user.id == participation.user_id do + activities = + participation.conversation.ap_id + |> ActivityPub.fetch_activities_for_context(params) + |> Enum.reverse() + + conn + |> add_link_headers( + :conversation_statuses, + activities, + participation_id, + params, + nil, + &pleroma_api_url/4 + ) + |> put_view(StatusView) + |> render("index.json", %{activities: activities, for: user, as: :activity}) + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 0689d69fb..40298538a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -257,6 +257,15 @@ defmodule Pleroma.Web.Router do end end + scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do + pipe_through(:authenticated_api) + + scope [] do + pipe_through(:oauth_write) + get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) + end + end + scope "/api/v1", Pleroma.Web.MastodonAPI do pipe_through(:authenticated_api) diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index af320f31f..7510c8def 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -239,7 +239,7 @@ test "for public posts, not a reply" do mentioned_user = insert(:user) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public") + {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public", nil) assert length(to) == 2 assert length(cc) == 1 @@ -256,7 +256,7 @@ test "for public posts, a reply" do {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"}) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public") + {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public", nil) assert length(to) == 3 assert length(cc) == 1 @@ -272,7 +272,7 @@ test "for unlisted posts, not a reply" do mentioned_user = insert(:user) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted") + {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted", nil) assert length(to) == 2 assert length(cc) == 1 @@ -289,7 +289,7 @@ test "for unlisted posts, a reply" do {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"}) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted") + {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted", nil) assert length(to) == 3 assert length(cc) == 1 @@ -305,7 +305,7 @@ test "for private posts, not a reply" do mentioned_user = insert(:user) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private") + {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil) assert length(to) == 2 assert length(cc) == 0 @@ -321,7 +321,7 @@ test "for private posts, a reply" do {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"}) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private") + {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil) assert length(to) == 3 assert length(cc) == 0 @@ -336,7 +336,7 @@ test "for direct posts, not a reply" do mentioned_user = insert(:user) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct") + {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil) assert length(to) == 1 assert length(cc) == 0 @@ -351,7 +351,7 @@ test "for direct posts, a reply" do {:ok, activity} = CommonAPI.post(third_user, %{"status" => "uguu"}) mentions = [mentioned_user.ap_id] - {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct") + {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil) assert length(to) == 2 assert length(cc) == 0 diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs new file mode 100644 index 000000000..43104e36e --- /dev/null +++ b/test/web/pleroma_api/pleroma_api_controller_test.exs @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Conversation.Participation + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + test "/api/v1/pleroma/conversations/:id/statuses", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + {:ok, _activity} = + CommonAPI.post(user, %{"status" => "Hi @#{third_user.nickname}!", "visibility" => "direct"}) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) + + [participation] = Participation.for_user(other_user) + + {:ok, activity_two} = + CommonAPI.post(other_user, %{ + "status" => "Hi!", + "in_reply_to_status_id" => activity.id, + "in_reply_to_conversation_id" => participation.id + }) + + result = + conn + |> assign(:user, other_user) + |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses") + |> json_response(200) + + assert length(result) == 2 + + id_one = activity.id + id_two = activity_two.id + assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result + end +end From 8815f07058f4bdf61355758cbe740288e9551435 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 2 Aug 2019 23:30:47 +0200 Subject: [PATCH 075/202] tasks/pleroma/user.ex: Fix documentation of --max-use and --expire-at Closes: https://git.pleroma.social/pleroma/pleroma/issues/1155 [ci skip] --- lib/mix/tasks/pleroma/user.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index c9b84b8f9..a3f8bc945 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -31,8 +31,8 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user invite [OPTION...] Options: - - `--expires_at DATE` - last day on which token is active (e.g. "2019-04-05") - - `--max_use NUMBER` - maximum numbers of token uses + - `--expires-at DATE` - last day on which token is active (e.g. "2019-04-05") + - `--max-use NUMBER` - maximum numbers of token uses ## List generated invites From 7efca4317b568c408a10b71799f9b8261ac5e8e6 Mon Sep 17 00:00:00 2001 From: Ashlynn Anderson Date: Wed, 31 Jul 2019 19:35:14 -0400 Subject: [PATCH 076/202] Basic working Dockerfile No fancy script or minit automatic migration, etc, but if you start the docker image and go in and manually do everything, it works. --- Dockerfile | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..667c01b39 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +FROM rinpatch/elixir:1.9.0-rc.0-alpine as build + +COPY . . + +ENV MIX_ENV prod + +RUN apk add git gcc g++ musl-dev make &&\ + echo "import Mix.Config" > config/prod.secret.exs &&\ + mix local.hex --force &&\ + mix local.rebar --force + +RUN mix deps.get --only prod &&\ + mkdir release &&\ + mix release --path release + +FROM alpine:latest + +RUN echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\ + apk update &&\ + apk add ncurses postgresql-client + +RUN adduser --system --shell /bin/false --home /opt/pleroma pleroma &&\ + mkdir -p /var/lib/pleroma/uploads &&\ + chown -R pleroma /var/lib/pleroma &&\ + mkdir -p /var/lib/pleroma/static &&\ + chown -R pleroma /var/lib/pleroma &&\ + mkdir -p /etc/pleroma &&\ + chown -R pleroma /etc/pleroma + +USER pleroma + +COPY --from=build --chown=pleroma:0 /release/ /opt/pleroma/ From 4a418698db71016447f2f246f7c5579b3dc0b08c Mon Sep 17 00:00:00 2001 From: Ashlynn Anderson Date: Fri, 2 Aug 2019 22:28:48 -0400 Subject: [PATCH 077/202] Create docker.exs and docker-entrypoint + round out Dockerfile At this point, the implementation is completely working and has been tested running live and federating with other instances. --- Dockerfile | 23 ++++++++++----- config/docker.exs | 67 ++++++++++++++++++++++++++++++++++++++++++++ docker-entrypoint.sh | 14 +++++++++ 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 config/docker.exs create mode 100755 docker-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 667c01b39..2f438c952 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM rinpatch/elixir:1.9.0-rc.0-alpine as build COPY . . -ENV MIX_ENV prod +ENV MIX_ENV=prod RUN apk add git gcc g++ musl-dev make &&\ echo "import Mix.Config" > config/prod.secret.exs &&\ @@ -15,18 +15,27 @@ RUN mix deps.get --only prod &&\ FROM alpine:latest +ARG HOME=/opt/pleroma +ARG DATA=/var/lib/pleroma + RUN echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\ apk update &&\ apk add ncurses postgresql-client -RUN adduser --system --shell /bin/false --home /opt/pleroma pleroma &&\ - mkdir -p /var/lib/pleroma/uploads &&\ - chown -R pleroma /var/lib/pleroma &&\ - mkdir -p /var/lib/pleroma/static &&\ - chown -R pleroma /var/lib/pleroma &&\ +RUN adduser --system --shell /bin/false --home ${HOME} pleroma &&\ + mkdir -p ${DATA}/uploads &&\ + mkdir -p ${DATA}/static &&\ + chown -R pleroma ${DATA} &&\ mkdir -p /etc/pleroma &&\ chown -R pleroma /etc/pleroma USER pleroma -COPY --from=build --chown=pleroma:0 /release/ /opt/pleroma/ +COPY --from=build --chown=pleroma:0 /release ${HOME} + +COPY ./config/docker.exs /etc/pleroma/config.exs +COPY ./docker-entrypoint.sh ${HOME} + +EXPOSE 4000 + +ENTRYPOINT ["/opt/pleroma/docker-entrypoint.sh"] diff --git a/config/docker.exs b/config/docker.exs new file mode 100644 index 000000000..c07f0b753 --- /dev/null +++ b/config/docker.exs @@ -0,0 +1,67 @@ +import Config + +config :pleroma, Pleroma.Web.Endpoint, + url: [host: System.get_env("DOMAIN", "localhost"), scheme: "https", port: 443], + http: [ip: {0, 0, 0, 0}, port: 4000] + +config :pleroma, :instance, + name: System.get_env("INSTANCE_NAME", "Pleroma"), + email: System.get_env("ADMIN_EMAIL"), + notify_email: System.get_env("NOTIFY_EMAIL"), + limit: 5000, + registrations_open: false, + dynamic_configuration: true + +config :pleroma, Pleroma.Repo, + adapter: Ecto.Adapters.Postgres, + username: System.get_env("DB_USER", "pleroma"), + password: System.fetch_env!("DB_PASS"), + database: System.get_env("DB_NAME", "pleroma"), + hostname: System.get_env("DB_HOST", "db"), + pool_size: 10 + +# Configure web push notifications +config :web_push_encryption, :vapid_details, + subject: "mailto:#{System.get_env("NOTIFY_EMAIL")}" + +config :pleroma, :database, rum_enabled: false +config :pleroma, :instance, static_dir: "/var/lib/pleroma/static" +config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads" + +# We can't store the secrets in this file, since this is baked into the docker image +if not File.exists?("/var/lib/pleroma/secret.exs") do + secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64) + signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8) + {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1) + + secret_file = EEx.eval_string( + """ + import Config + + config :pleroma, Pleroma.Web.Endpoint, + secret_key_base: "<%= secret %>", + signing_salt: "<%= signing_salt %>" + + config :web_push_encryption, :vapid_details, + public_key: "<%= web_push_public_key %>", + private_key: "<%= web_push_private_key %>" + """, + secret: secret, + signing_salt: signing_salt, + web_push_public_key: Base.url_encode64(web_push_public_key, padding: false), + web_push_private_key: Base.url_encode64(web_push_private_key, padding: false) + ) + + File.write("/var/lib/pleroma/secret.exs", secret_file) +end + +import_config("/var/lib/pleroma/secret.exs") + +# For additional user config +if File.exists?("/var/lib/pleroma/config.exs"), + do: import_config("/var/lib/pleroma/config.exs"), + else: File.write("/var/lib/pleroma/config.exs", """ + import Config + + # For additional configuration outside of environmental variables + """) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 000000000..f56f8c50a --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/ash + +set -e + +echo "-- Waiting for database..." +while ! pg_isready -U ${DB_USER:-pleroma} -d postgres://${DB_HOST:-db}:5432/${DB_NAME:-pleroma} -t 1; do + sleep 1s +done + +echo "-- Running migrations..." +$HOME/bin/pleroma_ctl migrate + +echo "-- Starting!" +exec $HOME/bin/pleroma start From c86db959cb3a3f4a4f79833747d5fa8ecff0d0c7 Mon Sep 17 00:00:00 2001 From: Ashlynn Anderson Date: Fri, 2 Aug 2019 22:40:31 -0400 Subject: [PATCH 078/202] Optimize Dockerfile Just merging RUNs to decrease the number of layers --- Dockerfile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2f438c952..268ec61dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,9 +7,8 @@ ENV MIX_ENV=prod RUN apk add git gcc g++ musl-dev make &&\ echo "import Mix.Config" > config/prod.secret.exs &&\ mix local.hex --force &&\ - mix local.rebar --force - -RUN mix deps.get --only prod &&\ + mix local.rebar --force &&\ + mix deps.get --only prod &&\ mkdir release &&\ mix release --path release @@ -20,9 +19,8 @@ ARG DATA=/var/lib/pleroma RUN echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\ apk update &&\ - apk add ncurses postgresql-client - -RUN adduser --system --shell /bin/false --home ${HOME} pleroma &&\ + apk add ncurses postgresql-client &&\ + adduser --system --shell /bin/false --home ${HOME} pleroma &&\ mkdir -p ${DATA}/uploads &&\ mkdir -p ${DATA}/static &&\ chown -R pleroma ${DATA} &&\ From 04327721d73733c1052d284adca12b949ce61045 Mon Sep 17 00:00:00 2001 From: Ashlynn Anderson Date: Fri, 2 Aug 2019 23:33:47 -0400 Subject: [PATCH 079/202] Add .dockerignore --- .dockerignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..c5ef89b86 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.* +*.md +AGPL-3 +CC-BY-SA-4.0 +COPYING +*file +elixir_buildpack.config +docs/ +test/ + +# Required to get version +!.git From a187dbb326f8fa3dfe19a113f4db5ed0a95435cb Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 3 Aug 2019 17:24:57 +0000 Subject: [PATCH 080/202] Add preferredUsername to service actors so Mastodon can resolve them --- lib/pleroma/web/activity_pub/views/user_view.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 639519e0a..4a83ac980 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -45,6 +45,7 @@ def render("service.json", %{user: user}) do "following" => "#{user.ap_id}/following", "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", + "preferredUsername" => user.nickname, "name" => "Pleroma", "summary" => "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", From 4007717534f9cc880b808b91ba6be5801afb71a0 Mon Sep 17 00:00:00 2001 From: Ashlynn Anderson Date: Sat, 3 Aug 2019 13:42:57 -0400 Subject: [PATCH 081/202] Run mix format --- config/docker.exs | 53 ++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/config/docker.exs b/config/docker.exs index c07f0b753..63ab4cdee 100644 --- a/config/docker.exs +++ b/config/docker.exs @@ -1,8 +1,8 @@ import Config config :pleroma, Pleroma.Web.Endpoint, - url: [host: System.get_env("DOMAIN", "localhost"), scheme: "https", port: 443], - http: [ip: {0, 0, 0, 0}, port: 4000] + url: [host: System.get_env("DOMAIN", "localhost"), scheme: "https", port: 443], + http: [ip: {0, 0, 0, 0}, port: 4000] config :pleroma, :instance, name: System.get_env("INSTANCE_NAME", "Pleroma"), @@ -21,8 +21,7 @@ pool_size: 10 # Configure web push notifications -config :web_push_encryption, :vapid_details, - subject: "mailto:#{System.get_env("NOTIFY_EMAIL")}" +config :web_push_encryption, :vapid_details, subject: "mailto:#{System.get_env("NOTIFY_EMAIL")}" config :pleroma, :database, rum_enabled: false config :pleroma, :instance, static_dir: "/var/lib/pleroma/static" @@ -34,23 +33,24 @@ signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8) {web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1) - secret_file = EEx.eval_string( - """ - import Config - - config :pleroma, Pleroma.Web.Endpoint, - secret_key_base: "<%= secret %>", - signing_salt: "<%= signing_salt %>" - - config :web_push_encryption, :vapid_details, - public_key: "<%= web_push_public_key %>", - private_key: "<%= web_push_private_key %>" - """, - secret: secret, - signing_salt: signing_salt, - web_push_public_key: Base.url_encode64(web_push_public_key, padding: false), - web_push_private_key: Base.url_encode64(web_push_private_key, padding: false) - ) + secret_file = + EEx.eval_string( + """ + import Config + + config :pleroma, Pleroma.Web.Endpoint, + secret_key_base: "<%= secret %>", + signing_salt: "<%= signing_salt %>" + + config :web_push_encryption, :vapid_details, + public_key: "<%= web_push_public_key %>", + private_key: "<%= web_push_private_key %>" + """, + secret: secret, + signing_salt: signing_salt, + web_push_public_key: Base.url_encode64(web_push_public_key, padding: false), + web_push_private_key: Base.url_encode64(web_push_private_key, padding: false) + ) File.write("/var/lib/pleroma/secret.exs", secret_file) end @@ -60,8 +60,9 @@ # For additional user config if File.exists?("/var/lib/pleroma/config.exs"), do: import_config("/var/lib/pleroma/config.exs"), - else: File.write("/var/lib/pleroma/config.exs", """ - import Config - - # For additional configuration outside of environmental variables - """) + else: + File.write("/var/lib/pleroma/config.exs", """ + import Config + + # For additional configuration outside of environmental variables + """) From 8b2fa31fed1a970c75e077d419dc78be7fc73a93 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Sat, 3 Aug 2019 18:12:38 +0000 Subject: [PATCH 082/202] Handle MRF rejections of incoming AP activities --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 +++ test/web/federator_test.exs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 07a65127b..2877c029e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -267,6 +267,9 @@ def create(%{to: to, actor: actor, context: context, object: object} = params, f else {:fake, true, activity} -> {:ok, activity} + + {:error, message} -> + {:error, message} end end diff --git a/test/web/federator_test.exs b/test/web/federator_test.exs index 6e143eee4..73cfaa8f1 100644 --- a/test/web/federator_test.exs +++ b/test/web/federator_test.exs @@ -229,5 +229,21 @@ test "rejects incoming AP docs with incorrect origin" do :error = Federator.incoming_ap_doc(params) end + + test "it does not crash if MRF rejects the post" do + policies = Pleroma.Config.get([:instance, :rewrite_policy]) + mrf_keyword_policy = Pleroma.Config.get(:mrf_keyword) + Pleroma.Config.put([:mrf_keyword, :reject], ["lain"]) + Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.KeywordPolicy) + + params = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + + assert Federator.incoming_ap_doc(params) == :error + + Pleroma.Config.put([:instance, :rewrite_policy], policies) + Pleroma.Config.put(:mrf_keyword, mrf_keyword_policy) + end end end From 040347b24820e2773c45a38d4cb6a184d6b14366 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Sat, 3 Aug 2019 18:13:20 +0000 Subject: [PATCH 083/202] Remove spaces from the domain search --- lib/pleroma/user/search.ex | 2 +- test/web/mastodon_api/search_controller_test.exs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex index 46620b89a..6fb2c2352 100644 --- a/lib/pleroma/user/search.ex +++ b/lib/pleroma/user/search.ex @@ -44,7 +44,7 @@ defp format_query(query_string) do query_string = String.trim_leading(query_string, "@") with [name, domain] <- String.split(query_string, "@"), - formatted_domain <- String.replace(domain, ~r/[!-\-|@|[-`|{-~|\/|:]+/, "") do + formatted_domain <- String.replace(domain, ~r/[!-\-|@|[-`|{-~|\/|:|\s]+/, "") do name <> "@" <> to_string(:idna.encode(formatted_domain)) else _ -> query_string diff --git a/test/web/mastodon_api/search_controller_test.exs b/test/web/mastodon_api/search_controller_test.exs index 043b96c14..49c79ff0a 100644 --- a/test/web/mastodon_api/search_controller_test.exs +++ b/test/web/mastodon_api/search_controller_test.exs @@ -95,6 +95,18 @@ test "account search", %{conn: conn} do assert user_three.nickname in result_ids end + + test "returns account if query contains a space", %{conn: conn} do + user = insert(:user, %{nickname: "shp@shitposter.club"}) + + results = + conn + |> assign(:user, user) + |> get("/api/v1/accounts/search", %{"q" => "shp@shitposter.club xxx "}) + |> json_response(200) + + assert length(results) == 1 + end end describe ".search" do From de0f3b73dd7c76b6b19b38804f98f6e7ccba7222 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sat, 3 Aug 2019 18:16:09 +0000 Subject: [PATCH 084/202] Admin fixes --- docs/api/admin_api.md | 4 +++ .../web/admin_api/admin_api_controller.ex | 6 ++-- lib/pleroma/web/admin_api/config.ex | 15 +++++++-- .../admin_api/admin_api_controller_test.exs | 32 +++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md index 22873dde9..7ccb90836 100644 --- a/docs/api/admin_api.md +++ b/docs/api/admin_api.md @@ -627,6 +627,9 @@ Tuples can be passed as `{"tuple": ["first_val", Pleroma.Module, []]}`. Keywords can be passed as lists with 2 child tuples, e.g. `[{"tuple": ["first_val", Pleroma.Module]}, {"tuple": ["second_val", true]}]`. +If value contains list of settings `[subkey: val1, subkey2: val2, subkey3: val3]`, it's possible to remove only subkeys instead of all settings passing `subkeys` parameter. E.g.: +{"group": "pleroma", "key": "some_key", "delete": "true", "subkeys": [":subkey", ":subkey3"]}. + Compile time settings (need instance reboot): - all settings by this keys: - `:hackney_pools` @@ -645,6 +648,7 @@ Compile time settings (need instance reboot): - `key` (string or string with leading `:` for atoms) - `value` (string, [], {} or {"tuple": []}) - `delete` = true (optional, if parameter must be deleted) + - `subkeys` [(string with leading `:` for atoms)] (optional, works only if `delete=true` parameter is passed, otherwise will be ignored) ] - Request (example): diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index fcda57b3e..2d3d0adc4 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -402,9 +402,9 @@ def config_update(conn, %{"configs" => configs}) do if Pleroma.Config.get([:instance, :dynamic_configuration]) do updated = Enum.map(configs, fn - %{"group" => group, "key" => key, "delete" => "true"} -> - {:ok, _} = Config.delete(%{group: group, key: key}) - nil + %{"group" => group, "key" => key, "delete" => "true"} = params -> + {:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]}) + config %{"group" => group, "key" => key, "value" => value} -> {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value}) diff --git a/lib/pleroma/web/admin_api/config.ex b/lib/pleroma/web/admin_api/config.ex index dde05ea7b..a10cc779b 100644 --- a/lib/pleroma/web/admin_api/config.ex +++ b/lib/pleroma/web/admin_api/config.ex @@ -55,8 +55,19 @@ def update_or_create(params) do @spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()} def delete(params) do - with %Config{} = config <- Config.get_by_params(params) do - Repo.delete(config) + with %Config{} = config <- Config.get_by_params(Map.delete(params, :subkeys)) do + if params[:subkeys] do + updated_value = + Keyword.drop( + :erlang.binary_to_term(config.value), + Enum.map(params[:subkeys], &do_transform_string(&1)) + ) + + Config.update(config, %{value: updated_value}) + else + Repo.delete(config) + {:ok, nil} + end else nil -> err = diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index f61499a22..bcbc18639 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -1914,6 +1914,38 @@ test "queues key as atom", %{conn: conn} do ] } end + + test "delete part of settings by atom subkeys", %{conn: conn} do + config = + insert(:config, + key: "keyaa1", + value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") + ) + + conn = + post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{ + group: config.group, + key: config.key, + subkeys: [":subkey1", ":subkey3"], + delete: "true" + } + ] + }) + + assert( + json_response(conn, 200) == %{ + "configs" => [ + %{ + "group" => "pleroma", + "key" => "keyaa1", + "value" => [%{"tuple" => [":subkey2", "val2"]}] + } + ] + } + ) + end end describe "config mix tasks run" do From 16cfb89240f9f56752ba8d91d84ce81a70f8d6cf Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 3 Aug 2019 18:28:08 +0000 Subject: [PATCH 085/202] Only add `preferredUsername` to service actor json when the underlying user actually has a username --- lib/pleroma/web/activity_pub/views/user_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 4a83ac980..8fe38927f 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -45,7 +45,6 @@ def render("service.json", %{user: user}) do "following" => "#{user.ap_id}/following", "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", - "preferredUsername" => user.nickname, "name" => "Pleroma", "summary" => "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", @@ -58,6 +57,7 @@ def render("service.json", %{user: user}) do }, "endpoints" => endpoints } + |> Map.merge(if user.nickname == nil do %{} else %{ "preferredUsername" => user.nickname}) |> Map.merge(Utils.make_json_ld_header()) end From 1fce56c7dffb84917b6943cc5919ed76e06932a5 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 3 Aug 2019 18:37:20 +0000 Subject: [PATCH 086/202] Refactor --- lib/pleroma/web/activity_pub/views/user_view.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 8fe38927f..06c9e1c71 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -57,7 +57,6 @@ def render("service.json", %{user: user}) do }, "endpoints" => endpoints } - |> Map.merge(if user.nickname == nil do %{} else %{ "preferredUsername" => user.nickname}) |> Map.merge(Utils.make_json_ld_header()) end @@ -66,7 +65,7 @@ def render("user.json", %{user: %User{nickname: nil} = user}), do: render("service.json", %{user: user}) def render("user.json", %{user: %User{nickname: "internal." <> _} = user}), - do: render("service.json", %{user: user}) + do: render("service.json", %{user: user}) |> Map.put("preferredUsername", user.nickname) def render("user.json", %{user: user}) do {:ok, user} = User.ensure_keys_present(user) From a035ab8c1d1589a97816d17dac8d60fb4b2275b2 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sat, 3 Aug 2019 22:56:20 +0200 Subject: [PATCH 087/202] templates/layout/app.html.eex: Style anchors [ci skip] --- lib/pleroma/web/templates/layout/app.html.eex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index b3cf9ed11..5836ec1e0 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -36,6 +36,11 @@ margin-bottom: 20px; } + a { + color: color: #d8a070; + text-decoration: none; + } + form { width: 100%; } From cef3af5536c16ff357fe2e0ed8c560aff16c62de Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 3 Aug 2019 23:17:17 +0000 Subject: [PATCH 088/202] tasks: relay: add list task --- CHANGELOG.md | 1 + lib/mix/tasks/pleroma/relay.ex | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fa9ffd9b..2b0a6189a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ActivityPub: Optional signing of ActivityPub object fetches. - Admin API: Endpoint for fetching latest user's statuses - Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=` for resending account confirmation. +- Relays: Added a task to list relay subscriptions. ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex index 83ed0ed02..c7324fff6 100644 --- a/lib/mix/tasks/pleroma/relay.ex +++ b/lib/mix/tasks/pleroma/relay.ex @@ -5,6 +5,7 @@ defmodule Mix.Tasks.Pleroma.Relay do use Mix.Task import Mix.Pleroma + alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay @shortdoc "Manages remote relays" @@ -22,6 +23,10 @@ defmodule Mix.Tasks.Pleroma.Relay do ``mix pleroma.relay unfollow `` Example: ``mix pleroma.relay unfollow https://example.org/relay`` + + ## List relay subscriptions + + ``mix pleroma.relay list`` """ def run(["follow", target]) do start_pleroma() @@ -44,4 +49,19 @@ def run(["unfollow", target]) do {:error, e} -> shell_error("Error while following #{target}: #{inspect(e)}") end end + + def run(["list"]) do + start_pleroma() + + with %User{} = user <- Relay.get_actor() do + user.following + |> Enum.each(fn entry -> + URI.parse(entry) + |> Map.get(:host) + |> shell_info() + end) + else + e -> shell_error("Error while fetching relay subscription list: #{inspect(e)}") + end + end end From c10a3e035b2761b1d8419d39b8392d499abe9aae Mon Sep 17 00:00:00 2001 From: Pierce McGoran Date: Sun, 4 Aug 2019 03:01:21 +0000 Subject: [PATCH 089/202] Update link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 41d454a03..5aad34ccc 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ If you want to run your own server, feel free to contact us at @lain@pleroma.soy Currently Pleroma is not packaged by any OS/Distros, but feel free to reach out to us at [#pleroma-dev on freenode](https://webchat.freenode.net/?channels=%23pleroma-dev) or via matrix at for assistance. If you want to change default options in your Pleroma package, please **discuss it with us first**. ### Docker -While we don’t provide docker files, other people have written very good ones. Take a look at or . +While we don’t provide docker files, other people have written very good ones. Take a look at or . ### Dependencies From 9b9453ceaf492ef3af18c12ce67e144a718fd65a Mon Sep 17 00:00:00 2001 From: Pierce McGoran Date: Sun, 4 Aug 2019 03:12:38 +0000 Subject: [PATCH 090/202] Fix some typos and rework a few lines in howto_mediaproxy.md --- docs/config/howto_mediaproxy.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/howto_mediaproxy.md b/docs/config/howto_mediaproxy.md index ed70c3ed4..16c40c5db 100644 --- a/docs/config/howto_mediaproxy.md +++ b/docs/config/howto_mediaproxy.md @@ -1,8 +1,8 @@ # How to activate mediaproxy ## Explanation -Without the `mediaproxy` function, Pleroma don't store any remote content like pictures, video etc. locally. So every time you open Pleroma, the content is loaded from the source server, from where the post is coming. This can result in slowly loading content or/and increased bandwidth usage on the source server. -With the `mediaproxy` function you can use the cache ability of nginx, to cache these content, so user can access it faster, cause it's loaded from your server. +Without the `mediaproxy` function, Pleroma doesn't store any remote content like pictures, video etc. locally. So every time you open Pleroma, the content is loaded from the source server, from where the post is coming. This can result in slowly loading content or/and increased bandwidth usage on the source server. +With the `mediaproxy` function you can use nginx to cache this content, so users can access it faster, because it's loaded from your server. ## Activate it From 39c7bbe18fcbff608bbc0b72ec6134872a1c946a Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Sun, 4 Aug 2019 04:32:45 +0000 Subject: [PATCH 091/202] Remove longfox emoji set --- CHANGELOG.md | 3 +++ config/emoji.txt | 28 ---------------------------- priv/static/emoji/f_00b.png | Bin 371 -> 0 bytes priv/static/emoji/f_00b11b.png | Bin 661 -> 0 bytes priv/static/emoji/f_00b33b.png | Bin 662 -> 0 bytes priv/static/emoji/f_00h.png | Bin 7522 -> 0 bytes priv/static/emoji/f_00t.png | Bin 541 -> 0 bytes priv/static/emoji/f_01b.png | Bin 4510 -> 0 bytes priv/static/emoji/f_03b.png | Bin 2872 -> 0 bytes priv/static/emoji/f_10b.png | Bin 2849 -> 0 bytes priv/static/emoji/f_11b.png | Bin 447 -> 0 bytes priv/static/emoji/f_11b00b.png | Bin 615 -> 0 bytes priv/static/emoji/f_11b22b.png | Bin 618 -> 0 bytes priv/static/emoji/f_11h.png | Bin 7314 -> 0 bytes priv/static/emoji/f_11t.png | Bin 559 -> 0 bytes priv/static/emoji/f_12b.png | Bin 4352 -> 0 bytes priv/static/emoji/f_21b.png | Bin 2900 -> 0 bytes priv/static/emoji/f_22b.png | Bin 386 -> 0 bytes priv/static/emoji/f_22b11b.png | Bin 666 -> 0 bytes priv/static/emoji/f_22b33b.png | Bin 663 -> 0 bytes priv/static/emoji/f_22h.png | Bin 7448 -> 0 bytes priv/static/emoji/f_22t.png | Bin 549 -> 0 bytes priv/static/emoji/f_23b.png | Bin 4334 -> 0 bytes priv/static/emoji/f_30b.png | Bin 4379 -> 0 bytes priv/static/emoji/f_32b.png | Bin 2921 -> 0 bytes priv/static/emoji/f_33b.png | Bin 459 -> 0 bytes priv/static/emoji/f_33b00b.png | Bin 611 -> 0 bytes priv/static/emoji/f_33b22b.png | Bin 623 -> 0 bytes priv/static/emoji/f_33h.png | Bin 7246 -> 0 bytes priv/static/emoji/f_33t.png | Bin 563 -> 0 bytes 30 files changed, 3 insertions(+), 28 deletions(-) delete mode 100644 priv/static/emoji/f_00b.png delete mode 100644 priv/static/emoji/f_00b11b.png delete mode 100644 priv/static/emoji/f_00b33b.png delete mode 100644 priv/static/emoji/f_00h.png delete mode 100644 priv/static/emoji/f_00t.png delete mode 100644 priv/static/emoji/f_01b.png delete mode 100644 priv/static/emoji/f_03b.png delete mode 100644 priv/static/emoji/f_10b.png delete mode 100644 priv/static/emoji/f_11b.png delete mode 100644 priv/static/emoji/f_11b00b.png delete mode 100644 priv/static/emoji/f_11b22b.png delete mode 100644 priv/static/emoji/f_11h.png delete mode 100644 priv/static/emoji/f_11t.png delete mode 100644 priv/static/emoji/f_12b.png delete mode 100644 priv/static/emoji/f_21b.png delete mode 100644 priv/static/emoji/f_22b.png delete mode 100644 priv/static/emoji/f_22b11b.png delete mode 100644 priv/static/emoji/f_22b33b.png delete mode 100644 priv/static/emoji/f_22h.png delete mode 100644 priv/static/emoji/f_22t.png delete mode 100644 priv/static/emoji/f_23b.png delete mode 100644 priv/static/emoji/f_30b.png delete mode 100644 priv/static/emoji/f_32b.png delete mode 100644 priv/static/emoji/f_33b.png delete mode 100644 priv/static/emoji/f_33b00b.png delete mode 100644 priv/static/emoji/f_33b22b.png delete mode 100644 priv/static/emoji/f_33h.png delete mode 100644 priv/static/emoji/f_33t.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fa9ffd9b..fc4d08aaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - RichMedia: parsers and their order are configured in `rich_media` config. - RichMedia: add the rich media ttl based on image expiration time. +### Removed +- Emoji: Remove longfox emojis. + ## [1.0.1] - 2019-07-14 ### Security - OStatus: fix an object spoofing vulnerability. diff --git a/config/emoji.txt b/config/emoji.txt index 79246f239..200768ad1 100644 --- a/config/emoji.txt +++ b/config/emoji.txt @@ -1,30 +1,2 @@ firefox, /emoji/Firefox.gif, Gif,Fun blank, /emoji/blank.png, Fun -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/priv/static/emoji/f_00b.png b/priv/static/emoji/f_00b.png deleted file mode 100644 index 3d00b89b02acbcf8cd3b4ff388e2f09f06c0aee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV6^gdaSW+oe0!bI&BamX_{aZe zX6tr}a(3}uiBn;ST_nxo^!x?ST;&xR;T&I=Y5KF@5L*AU=Eu*^3^kJaKZ=3oU;`6w zt-JN@_OS)(J9FoTt==ppyU6XFv-Q@zto0Qdv!5@2A)YF8{Drt>8YiOy14{#g00WZ) z0|x^mE>6Ry;sTMsi)`-2?%!(d_nO`LcJru6{1-oD!Mef_(Y8l8#ae0+Qj4GnKrsQ0BxFf%h37Z<-?u0A16 z0%&7iUS4i)Zd_bkLPEluhbQMeKD+2luf*|Y=HtyQr@90$%rZJNQStnAoeQ&!pRKZZvPkXO61C?m4Odqy zFDsK-P$bR6!;_w#o}ZszQBjeeo_cp*b52f9R%XV>_irB@={wym`gWb=lx$fcA))H( z>TJ8SnLw8@mIV0)GdMiEkp^U2d%8G=R4~3d7hKfBD8TSA^7h8u+uKV2Z+>FA`PXu_ zd+(S_YLj$D`dpGryVWPH+_lvB=A0d;+m$yu-R)Xhv@|bw<~P2=>o+AXT)oS2;W9VS zcr0Ko?~B*+5;?gCE_^ugqMzy5F?F@2t5&|04CXuV=FXp{UB3FKE`93KR8MeK7fkkZ za8X|!812_^Z|$k5gVTfq0*=PK`$wDhZOlBy8L)kA?#-Kbji0itxczRQ zjLfYfrZ4Y2`n0#rY3R~oMbTJPly#cZB6#lUqf2$wA9$%>7X~W&+3(A9;>FoTn(7Xv z)#}&gFch*wHJ!L`&SEn~no&*e=-n^DPb$~ueVl&%@vgml^-XkS4%;yBPFPsT{N%@E OkaAB~KbLh*2~7Y>h#0s4 diff --git a/priv/static/emoji/f_00b33b.png b/priv/static/emoji/f_00b33b.png deleted file mode 100644 index 8f4929297e401d8fc0b150c0080b989d974e00db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 662 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 diff --git a/priv/static/emoji/f_00t.png b/priv/static/emoji/f_00t.png deleted file mode 100644 index 31d98b4333b253da7c08b7925928d3750b816125..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 541 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 diff --git a/priv/static/emoji/f_03b.png b/priv/static/emoji/f_03b.png deleted file mode 100644 index 9e4ff1bf77074361c97d1ef8fcdc205575d03916..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2872 zcmV-83&-?{P)IBJ?$i+-Z@vlFUV9BP($f(i-vP~>_-AksZq0^Jz=J=J)l!7@>(&^R;_kcd z5=)4Km`6NLG$kr>lmLI7B4`dPSjZ0%o-?OTVB*B_7%*S}8a8amW$+RUh<-#>A`+qm z_;YL}MR1W20E5WI^Jg)2%4GEK-w)NRSLZUEBfck+h)9YO;Ll}n*en3T5IK3`7=HZm z2c)N`i=JT?(S?Y#C;|SO3?h0sfO&K0pljEzLWI>sSHjdN0VH6v6e8erLuAv&^?2a^ z`-KQ=h}#JHQ3A*pf$u6rwr$;vzJ2=$5#|u7gvn6?NLU^Up*cz*vU>GObnJMu5aB1H zCK0Jo0tl>@LSx7zGH%>hG;iLFOOQ|WCuBqkV7>?i@Oxe0vD>V8^_5pdHJD8_BjiL0 zV7>?<8#k;+N=h=9z)lP#B0Wj~(H}VN7Vw0_LA>?m8=@MFB`Oh-93_CDq__ZJA@HnN zz6?#9HsKN+BCa4JJxTzvZFJg8z*Ax=LicWBh(r&YB0ow1ft9L($j2XlBqaEmh=wQu zgao007d$g(&JYqTBxFVjVE){|3ZC4YY&2;c%O%Jq;)qC(5NQ@G|d#mTi3g}0DhtcAva0@^Lqk4970lJBA4JWAwNn0^QVTE z;zGp6HsTVjBFv8xK>ikS-`?G#9~exi@VJ9;xdVX9Pxt_h{=unv;IP|aw^<@cgd*_F zpF2lL@C2b!aAdu`;OIuZ=)`tboWEPQ7M#@S8?S4g5OasXybSP!OXYAloZ^dFAt#37 z+~H@Rd?X}DBceN5KgT+wbaUJyo)BEa2m%OB(+VrD-e(yZp za(1uoba|MEfddi*c54YA!&azg2Y#;`Ja^rB2e|)4bSLNcHZB4=zqJBMfb3tIAoIui z*!gXB?D#4M+rNzAe`Yyu-y(>UMQ^|LhL9ju z3GgoyZ~UJ1V*_meECyLWHRM%+6&~ND8@)mZ{EN+(hjQ5u1pQv{B*e#a0X8TB{u72I zAe;IKzC`ez;n2KCm?b}#`2e`QI&7ALayul-%gGW|V4xDdts6$J` zJIvv*auN78vfPOvj-0>#>dRaJA5mQi@LwR0M9BWNIktTogS?^1>|E|7W7psgqD+FK za$w2il>nE3yrD@nOQ?w*U&OFe zo4(h*0CRc6T!L~_1#+`@iYjoM65x_Z@PEC*;RR3eo`AUnC>IilBj$bj^cJt3DFH6k zl92O9J41r~Q@S&kFUZ^>^CjR7AO#2fGd(w_01ndb58PcTBpBCOcX^tN&p!W42r|HPhxO#{WqnfW1H2qi6Or^ zohPI8M$-vO07<(8e(r!jP`bE(u_1xYVr~@}IeaJ=AV}0!0!W~AbX*5?Obxc;Gt6V+ z&Oi?bjf1gu>eS&9JgWqdI5Ff^VE>dJd~3*@nr6yU;II{!y<_+U7a&IoAQ|2dp)=B`0{XiBSPR;$J9kZ7dFqc1U%B~<3^uz1c(4_QMvNx3gl9vL$ zH9WfHWupq%tyWWd0SfV z<6{%FBcl_re?&ZX4efyP+7KF5VCH?y6B1QG{xUFp*bs49brm8qvh|ntp6o##z$GZ0 zo($)_6co)!#=(*C;QyXeUV4E)+R|yF8m#cx7Tptu^mh$-_U_3QeZWmbWTZizDrnlE zDpK0iz};8Z#p`_=W6C?NacEQmT=P?rKPjul0?^mY>_hvmg~G#?grO_x7erko`+j60se#7My09 zHzau~XaUcok31X|SJI{tpAsi(RI7wn`^4hNm;`9^Qg|gG%&h|XJBBeY#4;ea5BTHv zU%3G1iKxkoL~+}u)iCSBw(u`X#lGS3$oj*aN5(t9sX|-AzRc~H-wg6>_`fp(9f+t& zLt;9CFCS?N-=Z{X63vky=eL%~`LzYJoZUwfFu4LS9T(5%iyw@A9}#tVhrnypDEdhP zUJ0@X$*%(Z(u(|@Bg>k>BFTqDbX zLs6Znb!t||VHzNvo|q_gXFx+ClAsYQJidjWB9`6=ju}0Y3s5K~g3+9k`#aUAen9?G zz?Xsi%+bsX`2wt1zJv?Fh*m^Y=RN`}zmCJjX~|Nn06#KzeC2!0qsyHN^6bjZ7F)q< ziKx%92dN6sv{0%5JHM%lgR}cFmk-Qgw@DO0NB-#(;-F|RBI@&O&1#j6Z~n2d3DN|} z{IQ<#PNBnYXHLy6O@MIFYuqr_u5DX&-E3Lv5}{w8X#vOF6sgYz@`j}_YrzSodBRd> z0eZ-XjErnj Wnd|l2N8F|W00003RzX=`6xmTY)Ni*_) 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 diff --git a/priv/static/emoji/f_11b00b.png b/priv/static/emoji/f_11b00b.png deleted file mode 100644 index c4c30e11f5c16d81c05217d2a109d27d89a73e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 615 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fsrG?C&U%V&CSjA_4WDx|No~C zZ$G?y^X>2dC+C)&>6N%J%jm)^<7cZZR#z+Y@bDBD7stiLd3$?)eE;VC+gD%z{(pFK z_VH%sGZPihOjLTZNNrh}4A8Xn^z?*;1aEJzho|NqZ)VBN%#4bP3J3@Y3=GUjPfbrx z&C1O9@b2};_iyhX>b|?b<=+0*yZf3S9O*mR!FQ~Y;aDT%>2A^U({b4j%g!Y6&P4IPREY^`68&isQ?g~Hq@=jHxp{ec`S|#lnVA_G8HI#| z+S=M`YisN4>l+#x^78Tu3JP*^a;mGVpDj^aP$d2E*?YcQo;DgTe~DWM4f2cZE% diff --git a/priv/static/emoji/f_11b22b.png b/priv/static/emoji/f_11b22b.png deleted file mode 100644 index 47425e06e2713254552d9081069ed7553f6181e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fsrG?C&U%V&CJa7_V)V!|No~C zZ$G?y{q67n$7dIv>JmIZUFZCC-RCO}7ZgeJ@$pquRK&%_eSH7s{o7Yx|Neh?a?bH) z<}(u&&rDQ$wnPnRPJVuVLPEmBQ*)0uvoJC;78De;wYAmO*4Ee8H#9U97Z>N{<>ln$ zR99C^Nl9^YbMx}@GBYy^2?=#3iFYQ7_oYfqNR#MKlbDh%`);lA+m#ycR%*Oiq5gWg z`kUqIZ`WB~m}PvjgYQ@)!?8xj)7_%?4|U(&-*Rt%>)n0L503PGc=zVx`?neCsp;vd zS(zD8QBeT_0fB*mPZp^yE0gi|_I!A9c6xexZf>rxug{ZnOV0F4T$p9_Y?a08YGocC z9wpI7o^R1%uzC3;cb(>KnV&Jc({El|VyP>`{b5yL zO8V3$P^`g0LrJ3cx_w@nA_>(OH8!n#mAreMhzwj7#8|Q`IOUtq#--7&Y0GD>-SNwP z^@hjd@)60E_vc^p2#?$U?T!G7dIaZB{ef?OJN4|RypB6OiEH=9U17<#ORk-l%6wY3 aHu3)RS+gW`A6wr7srPjCb6Mw<&;$S)^#2(E diff --git a/priv/static/emoji/f_11h.png b/priv/static/emoji/f_11h.png deleted file mode 100644 index 28342363a20b6dbdeb34a2fc4d30a9def0c3201f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7314 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 diff --git a/priv/static/emoji/f_11t.png b/priv/static/emoji/f_11t.png deleted file mode 100644 index dca67dc70ac3d8259ab7a62acea3d9298751abb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 559 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&H3s;ExB}^fgamJIuWx_AKHX8uIb+Ra8`*4}EtCXeDDwkY6x^!?PP{Kz59$i(^Oy zgGn3nCI%jj7yPUO32_(CH#Bj(JZw-%5Ln=%AT^s8Xk(I5gQeJo9tQoF`i2VJ0S#UM zf|$>2Y)E6NaID|S_^kUKKf4LjgN8~@4guS^NTAvRrvotzix^&hXT1qM2Ur>mdKI;Vst0M7f_6#xJL diff --git a/priv/static/emoji/f_12b.png b/priv/static/emoji/f_12b.png deleted file mode 100644 index 9925adb7cf6dc3af9218a7e2f258840c4df7b423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4352 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 GgeCxGV1L2@ diff --git a/priv/static/emoji/f_22b11b.png b/priv/static/emoji/f_22b11b.png deleted file mode 100644 index 4bdfb3107c69afa25b605a62a11f18e05155fe9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 666 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fsrG?C&U%Vjf;!R%FOux|NqDL zZ$G?y^X>2d2S@r&cZ*(_W&C!X<&gs@ifb{g#5AR;TfBWj|-~V^_H6Lqa zI5Sb{&2shrGzp+NIXO9jfq@z6srUA`9&2O-f`WpA;^N};^z_Wk%>4ZPii!#z9v(hE zzSY&r%gSUH6iGi@W$|Q@+Os8U&sQ3rpRRjhmeHAsisz^6oavP~-pqWwndMZM;FEJp z9-f^2@YLLgC+9pqyXe!0w;$iX@%8ob_V)Dl_R7u8O-M+1y+A3CZ{gDVK&-h$X`|rSJR_BK&HoGQ&Y?{8tt&ik5e-xey#csp;?JFM)z3^+I@ZW=cVF|@ zzyIIAef8np>-6;0fPjF4f&xZH#$%0)_x87Dq^AZ323Ay5;PGbWD z-mFk>XlUq66o0o;qrSeLmzTFQN&M|fjoR8;Zf@?o`&-)D+N7kU-mNu0*}-@JPR zRD99qzd-LXmIV0)GdMiEkp^Vjdb&7s*6nS_=iM;-zJF%S|M<=G zx<1bnm63e>nZ0S@%0m+~a#mF+%@o>PqBi@qf2hW^Q^BD^S7*(*D!rNM?6orvyPX>t z7@1f&1O(RRt$(+H^_N!j!X6`D{bYs3pFQn%_cZET#Xr4W-fsB8`T6ocr>uJ#_xN={ zbSOB0wLbYS50rI(zW&ee{ZCSPbXNX}pEmWXseW>TZ)&acBGq=ofJ>cTOWzoAalAK7Tdy5K}Va0fs7rr>mdKI;Vst0HhxxN&o-= diff --git a/priv/static/emoji/f_22h.png b/priv/static/emoji/f_22h.png deleted file mode 100644 index 3b27e2de8cd26a53d5e84c4f8e3ce7c469bb7abb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7448 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 WbP@pQG7Dn>0000z?{ diff --git a/priv/static/emoji/f_22t.png b/priv/static/emoji/f_22t.png deleted file mode 100644 index addd9fec78839c418422e4a56a402ee003dcd8c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 549 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 diff --git a/priv/static/emoji/f_33b00b.png b/priv/static/emoji/f_33b00b.png deleted file mode 100644 index 65b6e24b8fb55f67817d8508ccae91b85b5acfd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 611 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fsrG?C&U%VEiNwR;o(_bt^912 z#f4eM7iJlq>6LhLZppX5|3AEY^XbFe|NsB{`ugPN=BB5o1Jy4plXm=J95hho|OxdwV4$Bm@Km1O^61MMY(0W~8U5 zW~8TneE;^tyVnnn^xfUpd~bj2-Tf{14|SjJ7CqL;aIBH>WC!2*>AG*%S-x4W{(8Ck zn-%KsR%*Omsqt>D@sw=Y{xpdRX%c;@5}k?Sok`+CLPCs;jLgi;e0+Soyu94p+)`3f z)z#HGIXMLd1$lXS4Gj(T_4T#2wQX%}3yP$lEm6zQ&wqGwPDMq<^Oc6@r|X>R5`27i z(e0Nd&wzeoED7=pW^j0RBMr#r^mK6ysbGA2xzUX!QKI!>@iFt;IkyBE#kw5?LcdSg z^-ymC_YJ*;C9H1`srfL?IJ5pfpZp&E1C8u`rswu&E_$SK``*fR7k2#PI8YbLn_-f- zG$?j?Q10p~hdiK7SV6;eZte98JD09KQ?u+&Qf}(EmzU#a&V7Dg07Z4%oqM&Z+WOYF zLJnNm@pkIXWr0N~@&ebdt+_ev>w6jXoeW1GeRV6|ws$S#jk*n{>2-Chm^1D?UiiIR z?bD_BYa#dIfAmVr@j`X)TFWK-F7!?G)T8m2<|Zxf)O&mP$qN3{tKP83a!#$YosoVE Oq|npV&t;ucLK6T9k_2G@ diff --git a/priv/static/emoji/f_33b22b.png b/priv/static/emoji/f_33b22b.png deleted file mode 100644 index d71a8ddd484664537af3fbd9b3f2703f78193d71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fsrG?C&U%Vt*EHrjA) z;rZ#h=cntO>Jof>cG0)L|3AEY{prKo|NsAcdwXSOX6EPT1JyrUqIPDY(wT{h$D5fS zo}Bab@BjC2UwwT4CN3_nprC+}k@0vl%fnN16A}`ttE+Qza`N)>ii?XI8XD^B>uYOk z+uGWMgoK!xnR$76xw*Neq@<=~%l4;9Oh}XHOO@zM6z@zDf4k1|&2shE%hlhkP=B{l z zjP%rifPlcjz^JIGWo0r?7OADDr$0P7+uPfdhlgi%wequ778hn2o#~Z$a&C#QuTO4n z?gf|5a-iQBOM?7@862M7NCUD(JzX3_Dj46~Xmn#K6lwifd~EGZ)3*Wvjt!y{8FDpj zYpNQY7@3$Z>Z}T2l1O`Fe^~TBd%;6?@jlZt`!koET%7aUH?_5`^xgD&)|@NTn6!Aa zqkXTK%*t_p+HePG7Z5a*H1z*nX}LN#@^+g0=Sx}V;`rxn(PH>uMoV?-wMze;M_bpPsi~N@ zn?K_4u2+|~FTU4mf9&ABivK_V?^i@okHjfhy7Jz6)2nBvb8+)l@7NYD_435K>r$`J geLepsY|;w`hHaZ=?5^gR>;`G^boFyt=akR{02Y=Ag#Z8m diff --git a/priv/static/emoji/f_33h.png b/priv/static/emoji/f_33h.png deleted file mode 100644 index e141c51846c2072fb6722c83ef2c998e3978005d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7246 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 diff --git a/priv/static/emoji/f_33t.png b/priv/static/emoji/f_33t.png deleted file mode 100644 index d5a23073d9ebd7fee72e78191940db5fdf482ff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 563 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&H3s;ExB}^liV8kHz6C|n&sQ3r zpRRj;y3VOC!N+G8ef#_W!@Jj?KD_<^|G&4lS7v5rettes{j()%XC^A0nW%WYnfc+# zIbZ+&fB*K?$M@&R*PtGl|&lY6`8p>D_gTe~DWM4fVxrt9 From 3411f506b3bf2cbeeb7f3b9e746eab652f93d530 Mon Sep 17 00:00:00 2001 From: x0rz3q Date: Sun, 4 Aug 2019 14:35:45 +0000 Subject: [PATCH 092/202] Replace "impode" with "implode" for --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index 02f86dc16..50d6bfed4 100644 --- a/docs/config.md +++ b/docs/config.md @@ -25,7 +25,7 @@ At this time, write CNAME to CDN in public_endpoint. ## Pleroma.Upload.Filter.Mogrify -* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"impode", "1"}]`. +* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`. ## Pleroma.Upload.Filter.Dedupe From e8ad116c2a5a166613f9609c8fe2559af2b97505 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Sun, 4 Aug 2019 17:13:06 +0000 Subject: [PATCH 093/202] Do not add the "next" key to likes.json if there is no more items --- .../web/activity_pub/views/object_view.ex | 4 +- test/support/factory.ex | 4 +- .../activity_pub_controller_test.exs | 53 +++++++++++++++++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 6028b773c..94d05f49b 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -66,8 +66,10 @@ def collection(collection, iri, page) do "orderedItems" => items } - if offset < total do + if offset + length(items) < total do Map.put(map, "next", "#{iri}?page=#{page + 1}") + else + map end end end diff --git a/test/support/factory.ex b/test/support/factory.ex index c751546ce..8f638b98f 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -182,8 +182,8 @@ def announce_activity_factory(attrs \\ %{}) do } end - def like_activity_factory do - note_activity = insert(:note_activity) + def like_activity_factory(attrs \\ %{}) do + note_activity = attrs[:note_activity] || insert(:note_activity) object = Object.normalize(note_activity) user = insert(:user) diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 40344f17e..251055ee1 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -180,18 +180,65 @@ test "it returns 404 for tombstone objects", %{conn: conn} do end describe "/object/:uuid/likes" do - test "it returns the like activities in a collection", %{conn: conn} do + setup do like = insert(:like_activity) like_object_ap_id = Object.normalize(like).data["id"] - uuid = String.split(like_object_ap_id, "/") |> List.last() + uuid = + like_object_ap_id + |> String.split("/") + |> List.last() + + [id: like.data["id"], uuid: uuid] + end + + test "it returns the like activities in a collection", %{conn: conn, id: id, uuid: uuid} do result = conn |> put_req_header("accept", "application/activity+json") |> get("/objects/#{uuid}/likes") |> json_response(200) - assert List.first(result["first"]["orderedItems"])["id"] == like.data["id"] + assert List.first(result["first"]["orderedItems"])["id"] == id + assert result["type"] == "OrderedCollection" + assert result["totalItems"] == 1 + refute result["first"]["next"] + end + + test "it does not crash when page number is exceeded total pages", %{conn: conn, uuid: uuid} do + result = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/objects/#{uuid}/likes?page=2") + |> json_response(200) + + assert result["type"] == "OrderedCollectionPage" + assert result["totalItems"] == 1 + refute result["next"] + assert Enum.empty?(result["orderedItems"]) + end + + test "it contains the next key when likes count is more than 10", %{conn: conn} do + note = insert(:note_activity) + insert_list(11, :like_activity, note_activity: note) + + uuid = + note + |> Object.normalize() + |> Map.get(:data) + |> Map.get("id") + |> String.split("/") + |> List.last() + + result = + conn + |> put_req_header("accept", "application/activity+json") + |> get("/objects/#{uuid}/likes?page=1") + |> json_response(200) + + assert result["totalItems"] == 11 + assert length(result["orderedItems"]) == 10 + assert result["next"] end end From 96028cd585ac23a4233f41a6307d80979dd0e3a7 Mon Sep 17 00:00:00 2001 From: Eugenij Date: Sun, 4 Aug 2019 22:24:50 +0000 Subject: [PATCH 094/202] Remove Reply-To from report emails --- CHANGELOG.md | 2 ++ lib/pleroma/emails/admin_email.ex | 1 - test/emails/admin_email_test.exs | 14 +++++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cbbb88c..2713461ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Not being able to access the Mastodon FE login page on private instances - Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. +- Report email not being sent to admins when the reporter is a remote user ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) @@ -79,6 +80,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed - Emoji: Remove longfox emojis. +- Remove `Reply-To` header from report emails for admins. ## [1.0.1] - 2019-07-14 ### Security diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index d0e254362..c14be02dd 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -63,7 +63,6 @@ def report(to, reporter, account, statuses, comment) do new() |> to({to.name, to.email}) |> from({instance_name(), instance_notify_email()}) - |> reply_to({reporter.name, reporter.email}) |> subject("#{instance_name()} Report") |> html_body(html_body) end diff --git a/test/emails/admin_email_test.exs b/test/emails/admin_email_test.exs index 4bf54b0c2..9e83c73c6 100644 --- a/test/emails/admin_email_test.exs +++ b/test/emails/admin_email_test.exs @@ -24,7 +24,6 @@ test "build report email" do assert res.to == [{to_user.name, to_user.email}] assert res.from == {config[:name], config[:notify_email]} - assert res.reply_to == {reporter.name, reporter.email} assert res.subject == "#{config[:name]} Report" assert res.html_body == @@ -34,4 +33,17 @@ test "build report email" do status_url }\">#{status_url}\n \n

\n\n" end + + test "it works when the reporter is a remote user without email" do + config = Pleroma.Config.get(:instance) + to_user = insert(:user) + reporter = insert(:user, email: nil, local: false) + account = insert(:user) + + res = + AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment") + + assert res.to == [{to_user.name, to_user.email}] + assert res.from == {config[:name], config[:notify_email]} + end end From bbd9ed02576f1599e90f8575573fe6e935d32eae Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 5 Aug 2019 15:33:34 +0700 Subject: [PATCH 095/202] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd64b2259..e9d4e1710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added synchronization of following/followers counters for external users - Configuration: `enabled` option for `Pleroma.Emails.Mailer`, defaulting to `false`. - Configuration: Pleroma.Plugs.RateLimiter `bucket_name`, `params` options. +- Configuration: `user_bio_length` and `user_name_length` options. - Addressable lists - Twitter API: added rate limit for `/api/account/password_reset` endpoint. - ActivityPub: Add an internal service actor for fetching ActivityPub objects. From 3af6d14da769aa5adfdd6360b43c691fd8c8eed5 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 5 Aug 2019 15:09:19 +0200 Subject: [PATCH 096/202] Pleroma Conversations API: Add a way to set recipients. --- lib/pleroma/conversation/participation.ex | 20 ++++++++++ .../mastodon_api/views/conversation_view.ex | 13 +++++- .../web/pleroma_api/pleroma_api_controller.ex | 17 ++++++++ lib/pleroma/web/router.ex | 1 + .../mastodon_api/conversation_view_test.exs | 40 +++++++++++++++++++ .../pleroma_api_controller_test.exs | 31 ++++++++++++++ 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 test/web/mastodon_api/conversation_view_test.exs diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index f1e1a6958..acdee5517 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -99,4 +99,24 @@ def get(nil), do: nil def get(id) do Repo.get(__MODULE__, id) end + + def set_recipients(participation, user_ids) do + Repo.transaction(fn -> + query = + from(r in RecipientShip, + where: r.participation_id == ^participation.id + ) + + Repo.delete_all(query) + + users = + from(u in User, + where: u.id in ^user_ids + ) + |> Repo.all() + + RecipientShip.create(users, participation) + :ok + end) + end end diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 38bdec737..5adaecdb0 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.StatusView def render("participation.json", %{participation: participation, user: user}) do - participation = Repo.preload(participation, conversation: :users) + participation = Repo.preload(participation, conversation: :users, recipients: []) last_activity_id = with nil <- participation.last_activity_id do @@ -37,11 +37,20 @@ def render("participation.json", %{participation: participation, user: user}) do as: :user }) + recipients = + AccountView.render("accounts.json", %{ + users: participation.recipients, + as: :user + }) + %{ id: participation.id |> to_string(), accounts: accounts, unread: !participation.read, - last_status: last_status + last_status: last_status, + pleroma: %{ + recipients: recipients + } } end end diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index b677892ed..759d8aef0 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Repo def conversation_statuses( @@ -46,4 +47,20 @@ def conversation_statuses( |> render("index.json", %{activities: activities, for: user, as: :activity}) end end + + def update_conversation( + %{assigns: %{user: user}} = conn, + %{"id" => participation_id, "recipients" => recipients} + ) do + participation = + participation_id + |> Participation.get() + + with true <- user.id == participation.user_id, + {:ok, _} <- Participation.set_recipients(participation, recipients) do + conn + |> put_view(ConversationView) + |> render("participation.json", %{participation: participation, user: user}) + end + end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 40298538a..6cdef7e2f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -263,6 +263,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) + patch("/conversations/:id", PleromaAPIController, :update_conversation) end end diff --git a/test/web/mastodon_api/conversation_view_test.exs b/test/web/mastodon_api/conversation_view_test.exs new file mode 100644 index 000000000..2a4b41fa4 --- /dev/null +++ b/test/web/mastodon_api/conversation_view_test.exs @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do + use Pleroma.DataCase + + alias Pleroma.Web.CommonAPI + alias Pleroma.Conversation.Participation + alias Pleroma.Web.MastodonAPI.ConversationView + + import Pleroma.Factory + + test "represents a Mastodon Conversation entity" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}", "visibility" => "direct"}) + + [participation] = Participation.for_user_with_last_activity_id(user) + + assert participation + + conversation = + ConversationView.render("participation.json", %{participation: participation, user: user}) + + assert conversation.id == participation.id |> to_string() + assert conversation.last_status.id == activity.id + + assert [account] = conversation.accounts + assert account.id == other_user.id + + assert recipients = conversation.pleroma.recipients + recipient_ids = recipients |> Enum.map(& &1.id) + + assert user.id in recipient_ids + assert other_user.id in recipient_ids + end +end diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs index 43104e36e..7989defe0 100644 --- a/test/web/pleroma_api/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/pleroma_api_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do alias Pleroma.Conversation.Participation alias Pleroma.Web.CommonAPI + alias Pleroma.Repo import Pleroma.Factory @@ -42,4 +43,34 @@ test "/api/v1/pleroma/conversations/:id/statuses", %{conn: conn} do id_two = activity_two.id assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result end + + test "PATCH /api/v1/pleroma/conversations/:id", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = CommonAPI.post(user, %{"status" => "Hi", "visibility" => "direct"}) + + [participation] = Participation.for_user(user) + + participation = Repo.preload(participation, :recipients) + + assert [user] == participation.recipients + assert other_user not in participation.recipients + + result = + conn + |> assign(:user, user) + |> patch("/api/v1/pleroma/conversations/#{participation.id}", %{ + "recipients" => [user.id, other_user.id] + }) + |> json_response(200) + + assert result["id"] == participation.id |> to_string + + assert recipients = result["pleroma"]["recipients"] + recipient_ids = Enum.map(recipients, & &1["id"]) + + assert user.id in recipient_ids + assert other_user.id in recipient_ids + end end From b64b6fee2a78fbfbc557b89550128494ca7d2894 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 5 Aug 2019 15:33:22 +0200 Subject: [PATCH 097/202] CommonAPI: Replies to conversations also get the correct context id. --- lib/pleroma/web/common_api/common_api.ex | 2 +- lib/pleroma/web/common_api/utils.ex | 8 ++++++-- test/web/common_api/common_api_test.exs | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 86e95cd0f..72da46263 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -223,7 +223,7 @@ def post(user, %{"status" => status} = data) do {poll, poll_emoji} <- make_poll_data(data), {to, cc} <- get_to_and_cc(user, addressed_users, in_reply_to, visibility, in_reply_to_conversation), - context <- make_context(in_reply_to), + context <- make_context(in_reply_to, in_reply_to_conversation), cw <- data["spoiler_text"] || "", sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}), full_payload <- String.trim(status <> cw), diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index e70ba7d43..425b6d656 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -244,8 +244,12 @@ defp maybe_add_nsfw_tag({text, mentions, tags}, %{"sensitive" => sensitive}) defp maybe_add_nsfw_tag(data, _), do: data - def make_context(%Activity{data: %{"context" => context}}), do: context - def make_context(_), do: Utils.generate_context_id() + def make_context(_, %Participation{} = participation) do + Repo.preload(participation, :conversation).conversation.ap_id + end + + def make_context(%Activity{data: %{"context" => context}}, _), do: context + def make_context(_, _), do: Utils.generate_context_id() def maybe_add_attachments(parsed, _attachments, true = _no_links), do: parsed diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index e2a5bf117..454523349 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -9,10 +9,25 @@ defmodule Pleroma.Web.CommonAPITest do alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.CommonAPI import Pleroma.Factory + test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + + [participation] = Participation.for_user(user) + + {:ok, convo_reply} = + CommonAPI.post(user, %{"status" => ".", "in_reply_to_conversation_id" => participation.id}) + + assert Visibility.is_direct?(convo_reply) + + assert activity.data["context"] == convo_reply.data["context"] + end + test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do har = insert(:user) jafnhar = insert(:user) From ddabe7784b47939120a838b9c65381fd2262c161 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 5 Aug 2019 15:58:14 +0200 Subject: [PATCH 098/202] Pleroma Conversations: Document differences. --- docs/api/differences_in_mastoapi_responses.md | 8 +++++ docs/api/pleroma_api.md | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 1907d70c8..79ca531b8 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -59,12 +59,19 @@ Has these additional fields under the `pleroma` object: - `show_role`: boolean, nullable, true when the user wants his role (e.g admin, moderator) to be shown - `no_rich_text` - boolean, nullable, true when html tags are stripped from all statuses requested from the API +## Conversations + +Has an additional field under the `pleroma` object: + +- `recipients`: The list of the recipients of this Conversation. These will be addressed when replying to this conversation. + ## Account Search Behavior has changed: - `/api/v1/accounts/search`: Does not require authentication + ## Notifications Has these additional fields under the `pleroma` object: @@ -79,6 +86,7 @@ Additional parameters can be added to the JSON body/Form data: - `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint. - `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply. - `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`. +- `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`. ## PATCH `/api/v1/update_credentials` diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 5698e88ac..4323e59f0 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -319,3 +319,32 @@ See [Admin-API](Admin-API.md) "healthy": true # Instance state } ``` + +# Pleroma Conversations + +Pleroma Conversations have the same general structure that Mastodon Conversations have. The behavior differs in the following ways when using these endpoints: + +1. Pleroma Conversations never add or remove recipients, unless explicitly changed by the user. +2. Pleroma Conversations statuses can be requested by Conversation id. +3. Pleroma Conversations can be replied to. + +Conversations have the additional field "recipients" under the "pleroma" key. This holds a list of all the accounts that will receive a message in this conversation. + +The status posting endpoint takes an additional parameter, `in_reply_to_conversation_id`, which, when set, will set the visiblity to direct and address only the people who are the recipients of that Conversation. + + +## `GET /api/v1/pleroma/conversations/:id/statuses` +### Timeline for a given conversation +* Method `GET` +* Authentication: required +* Params: Like other timelines +* Response: JSON, statuses (200 - healthy, 503 unhealthy). + + +## `PATCH /api/v1/pleroma/conversations/:id` +### Update a conversation. Used to change the set of recipients. +* Method `PATCH` +* Authentication: required +* Params: + * `recipients`: A list of ids of users that should receive posts to this conversation. +* Response: JSON, statuses (200 - healthy, 503 unhealthy) From d6fe220e32d581220cc33f4f44d6517a401eabbf Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 5 Aug 2019 16:11:23 +0200 Subject: [PATCH 099/202] Linting. --- lib/pleroma/conversation/participation_recipient_ship.ex | 2 +- lib/pleroma/web/pleroma_api/pleroma_api_controller.ex | 6 +++--- test/web/mastodon_api/conversation_view_test.exs | 2 +- test/web/pleroma_api/pleroma_api_controller_test.exs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/conversation/participation_recipient_ship.ex b/lib/pleroma/conversation/participation_recipient_ship.ex index 27c0c89cd..932cbd04c 100644 --- a/lib/pleroma/conversation/participation_recipient_ship.ex +++ b/lib/pleroma/conversation/participation_recipient_ship.ex @@ -6,8 +6,8 @@ defmodule Pleroma.Conversation.Participation.RecipientShip do use Ecto.Schema alias Pleroma.Conversation.Participation - alias Pleroma.User alias Pleroma.Repo + alias Pleroma.User import Ecto.Changeset diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 759d8aef0..018564452 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -8,10 +8,10 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] alias Pleroma.Conversation.Participation - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.MastodonAPI.StatusView - alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Repo + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.ConversationView + alias Pleroma.Web.MastodonAPI.StatusView def conversation_statuses( %{assigns: %{user: user}} = conn, diff --git a/test/web/mastodon_api/conversation_view_test.exs b/test/web/mastodon_api/conversation_view_test.exs index 2a4b41fa4..e32cde5a8 100644 --- a/test/web/mastodon_api/conversation_view_test.exs +++ b/test/web/mastodon_api/conversation_view_test.exs @@ -5,8 +5,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do use Pleroma.DataCase - alias Pleroma.Web.CommonAPI alias Pleroma.Conversation.Participation + alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ConversationView import Pleroma.Factory diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs index 7989defe0..7c75fb229 100644 --- a/test/web/pleroma_api/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/pleroma_api_controller_test.exs @@ -6,8 +6,8 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Conversation.Participation - alias Pleroma.Web.CommonAPI alias Pleroma.Repo + alias Pleroma.Web.CommonAPI import Pleroma.Factory From bdc9a7222cca9988a238cbe76d0e51125a016f8d Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 5 Aug 2019 15:37:05 +0000 Subject: [PATCH 100/202] tests for CommonApi/Utils --- lib/pleroma/web/common_api/utils.ex | 104 +++++---- test/web/common_api/common_api_utils_test.exs | 219 +++++++++++++++++- 2 files changed, 278 insertions(+), 45 deletions(-) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index c8a743e8e..22c44a0a3 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -47,26 +47,43 @@ def get_replied_to_activity(id) when not is_nil(id) do def get_replied_to_activity(_), do: nil - def attachments_from_ids(data) do - if Map.has_key?(data, "descriptions") do - attachments_from_ids_descs(data["media_ids"], data["descriptions"]) - else - attachments_from_ids_no_descs(data["media_ids"]) - end + def attachments_from_ids(%{"media_ids" => ids, "descriptions" => desc} = _) do + attachments_from_ids_descs(ids, desc) end - def attachments_from_ids_no_descs(ids) do - Enum.map(ids || [], fn media_id -> - Repo.get(Object, media_id).data - end) + def attachments_from_ids(%{"media_ids" => ids} = _) do + attachments_from_ids_no_descs(ids) end + def attachments_from_ids(_), do: [] + + def attachments_from_ids_no_descs([]), do: [] + + def attachments_from_ids_no_descs(ids) do + Enum.map(ids, fn media_id -> + case Repo.get(Object, media_id) do + %Object{data: data} = _ -> data + _ -> nil + end + end) + |> Enum.filter(& &1) + end + + def attachments_from_ids_descs([], _), do: [] + def attachments_from_ids_descs(ids, descs_str) do {_, descs} = Jason.decode(descs_str) - Enum.map(ids || [], fn media_id -> - Map.put(Repo.get(Object, media_id).data, "name", descs[media_id]) + Enum.map(ids, fn media_id -> + case Repo.get(Object, media_id) do + %Object{data: data} = _ -> + Map.put(data, "name", descs[media_id]) + + _ -> + nil + end end) + |> Enum.filter(& &1) end @spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) :: @@ -247,20 +264,18 @@ def maybe_add_attachments({text, mentions, tags}, attachments, _no_links) do end def add_attachments(text, attachments) do - attachment_text = - Enum.map(attachments, fn - %{"url" => [%{"href" => href} | _]} = attachment -> - name = attachment["name"] || URI.decode(Path.basename(href)) - href = MediaProxy.url(href) - "
#{shortname(name)}" - - _ -> - "" - end) - + attachment_text = Enum.map(attachments, &build_attachment_link/1) Enum.join([text | attachment_text], "
") end + defp build_attachment_link(%{"url" => [%{"href" => href} | _]} = attachment) do + name = attachment["name"] || URI.decode(Path.basename(href)) + href = MediaProxy.url(href) + "#{shortname(name)}" + end + + defp build_attachment_link(_), do: "" + def format_input(text, format, options \\ []) @doc """ @@ -320,7 +335,7 @@ def make_note_data( sensitive \\ false, merge \\ %{} ) do - object = %{ + %{ "type" => "Note", "to" => to, "cc" => cc, @@ -330,18 +345,20 @@ def make_note_data( "context" => context, "attachment" => attachments, "actor" => actor, - "tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq() + "tag" => Keyword.values(tags) |> Enum.uniq() } + |> add_in_reply_to(in_reply_to) + |> Map.merge(merge) + end - object = - with false <- is_nil(in_reply_to), - %Object{} = in_reply_to_object <- Object.normalize(in_reply_to) do - Map.put(object, "inReplyTo", in_reply_to_object.data["id"]) - else - _ -> object - end + defp add_in_reply_to(object, nil), do: object - Map.merge(object, merge) + defp add_in_reply_to(object, in_reply_to) do + with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to) do + Map.put(object, "inReplyTo", in_reply_to_object.data["id"]) + else + _ -> object + end end def format_naive_asctime(date) do @@ -373,17 +390,16 @@ def to_masto_date(%NaiveDateTime{} = date) do |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false) end - def to_masto_date(date) do - try do - date - |> NaiveDateTime.from_iso8601!() - |> NaiveDateTime.to_iso8601() - |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false) - rescue - _e -> "" + def to_masto_date(date) when is_binary(date) do + with {:ok, date} <- NaiveDateTime.from_iso8601(date) do + to_masto_date(date) + else + _ -> "" end end + def to_masto_date(_), do: "" + defp shortname(name) do if String.length(name) < 30 do name @@ -428,7 +444,7 @@ def maybe_notify_mentioned_recipients( object_data = cond do - !is_nil(object) -> + not is_nil(object) -> object.data is_map(data["object"]) -> @@ -472,9 +488,9 @@ def maybe_notify_subscribers(recipients, _), do: recipients def maybe_extract_mentions(%{"tag" => tag}) do tag - |> Enum.filter(fn x -> is_map(x) end) - |> Enum.filter(fn x -> x["type"] == "Mention" end) + |> Enum.filter(fn x -> is_map(x) && x["type"] == "Mention" end) |> Enum.map(fn x -> x["href"] end) + |> Enum.uniq() end def maybe_extract_mentions(_), do: [] diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 4b5666c29..5989d7d29 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -306,7 +306,6 @@ test "for private posts, not a reply" do mentions = [mentioned_user.ap_id] {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private") - assert length(to) == 2 assert length(cc) == 0 @@ -380,4 +379,222 @@ test "get activity by object when type isn't `Create` " do assert like.data["object"] == activity.data["object"] end end + + describe "to_master_date/1" do + test "removes microseconds from date (NaiveDateTime)" do + assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z" + end + + test "removes microseconds from date (String)" do + assert Utils.to_masto_date("2015-01-23T23:50:07.123Z") == "2015-01-23T23:50:07.000Z" + end + + test "returns empty string when date invalid" do + assert Utils.to_masto_date("2015-01?23T23:50:07.123Z") == "" + end + end + + describe "conversation_id_to_context/1" do + test "returns id" do + object = insert(:note) + assert Utils.conversation_id_to_context(object.id) == object.data["id"] + end + + test "returns error if object not found" do + assert Utils.conversation_id_to_context("123") == {:error, "No such conversation"} + end + end + + describe "maybe_notify_mentioned_recipients/2" do + test "returns recipients when activity is not `Create`" do + activity = insert(:like_activity) + assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == ["test"] + end + + test "returns recipients from tag" do + user = insert(:user) + + object = + insert(:note, + user: user, + data: %{ + "tag" => [ + %{"type" => "Hashtag"}, + "", + %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"}, + %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}, + %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"} + ] + } + ) + + activity = insert(:note_activity, user: user, note: object) + + assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [ + "test", + "https://testing.pleroma.lol/users/lain", + "https://shitposter.club/user/5381" + ] + end + + test "returns recipients when object is map" do + user = insert(:user) + object = insert(:note, user: user) + + activity = + insert(:note_activity, + user: user, + note: object, + data_attrs: %{ + "object" => %{ + "tag" => [ + %{"type" => "Hashtag"}, + "", + %{"type" => "Mention", "href" => "https://testing.pleroma.lol/users/lain"}, + %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"}, + %{"type" => "Mention", "href" => "https://shitposter.club/user/5381"} + ] + } + } + ) + + Pleroma.Repo.delete(object) + + assert Utils.maybe_notify_mentioned_recipients(["test"], activity) == [ + "test", + "https://testing.pleroma.lol/users/lain", + "https://shitposter.club/user/5381" + ] + end + + test "returns recipients when object not found" do + user = insert(:user) + object = insert(:note, user: user) + + activity = insert(:note_activity, user: user, note: object) + Pleroma.Repo.delete(object) + + assert Utils.maybe_notify_mentioned_recipients(["test-test"], activity) == [ + "test-test" + ] + end + end + + describe "attachments_from_ids_descs/2" do + test "returns [] when attachment ids is empty" do + assert Utils.attachments_from_ids_descs([], "{}") == [] + end + + test "returns list attachments with desc" do + object = insert(:note) + desc = Jason.encode!(%{object.id => "test-desc"}) + + assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [ + Map.merge(object.data, %{"name" => "test-desc"}) + ] + end + end + + describe "attachments_from_ids/1" do + test "returns attachments with descs" do + object = insert(:note) + desc = Jason.encode!(%{object.id => "test-desc"}) + + assert Utils.attachments_from_ids(%{ + "media_ids" => ["#{object.id}"], + "descriptions" => desc + }) == [ + Map.merge(object.data, %{"name" => "test-desc"}) + ] + end + + test "returns attachments without descs" do + object = insert(:note) + assert Utils.attachments_from_ids(%{"media_ids" => ["#{object.id}"]}) == [object.data] + end + + test "returns [] when not pass media_ids" do + assert Utils.attachments_from_ids(%{}) == [] + end + end + + describe "maybe_add_list_data/3" do + test "adds list params when found user list" do + user = insert(:user) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user) + + assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == + %{ + additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id}, + object: %{"listMessage" => list.ap_id} + } + end + + test "returns original params when list not found" do + user = insert(:user) + {:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user)) + + assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) == + %{additional: %{}, object: %{}} + end + end + + describe "make_note_data/11" do + test "returns note data" do + user = insert(:user) + note = insert(:note) + user2 = insert(:user) + user3 = insert(:user) + + assert Utils.make_note_data( + user.ap_id, + [user2.ap_id], + "2hu", + "

This is :moominmamma: note

", + [], + note.id, + [name: "jimm"], + "test summary", + [user3.ap_id], + false, + %{"custom_tag" => "test"} + ) == %{ + "actor" => user.ap_id, + "attachment" => [], + "cc" => [user3.ap_id], + "content" => "

This is :moominmamma: note

", + "context" => "2hu", + "sensitive" => false, + "summary" => "test summary", + "tag" => ["jimm"], + "to" => [user2.ap_id], + "type" => "Note", + "custom_tag" => "test" + } + end + end + + describe "maybe_add_attachments/3" do + test "returns parsed results when no_links is true" do + assert Utils.maybe_add_attachments( + {"test", [], ["tags"]}, + [], + true + ) == {"test", [], ["tags"]} + end + + test "adds attachments to parsed results" do + attachment = %{"url" => [%{"href" => "SakuraPM.png"}]} + + assert Utils.maybe_add_attachments( + {"test", [], ["tags"]}, + [attachment], + false + ) == { + "test
SakuraPM.png", + [], + ["tags"] + } + end + end end From a49c92f6ae2dc68a80345cff4793820a75835eb1 Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 6 Aug 2019 14:51:17 +0200 Subject: [PATCH 101/202] Participation: Setting recipients will always add the owner. --- docs/api/pleroma_api.md | 2 +- lib/pleroma/conversation/participation.ex | 6 ++++++ test/conversation/participation_test.exs | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 4323e59f0..590f2a3fb 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -346,5 +346,5 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Method `PATCH` * Authentication: required * Params: - * `recipients`: A list of ids of users that should receive posts to this conversation. + * `recipients`: A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though. * Response: JSON, statuses (200 - healthy, 503 unhealthy) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index acdee5517..d17b6f7c5 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -101,6 +101,10 @@ def get(id) do end def set_recipients(participation, user_ids) do + user_ids = + [participation.user_id | user_ids] + |> Enum.uniq() + Repo.transaction(fn -> query = from(r in RecipientShip, @@ -118,5 +122,7 @@ def set_recipients(participation, user_ids) do RecipientShip.create(users, participation) :ok end) + + {:ok, Repo.preload(participation, :recipients, force: true)} end end diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 4a3c397bd..7958e8e89 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -132,4 +132,23 @@ test "Doesn't die when the conversation gets empty" do [] = Participation.for_user_with_last_activity_id(user) end + + test "it sets recipients, always keeping the owner of the participation even when not explicitly set" do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + [participation] = Participation.for_user_with_last_activity_id(user) + + participation = Repo.preload(participation, :recipients) + + assert participation.recipients |> length() == 1 + assert user in participation.recipients + + {:ok, participation} = Participation.set_recipients(participation, [other_user.id]) + + assert participation.recipients |> length() == 2 + assert user in participation.recipients + assert other_user in participation.recipients + end end From e4a01d253ef7ab09d028198e5e39b9aba357486c Mon Sep 17 00:00:00 2001 From: lain Date: Tue, 6 Aug 2019 15:06:19 +0200 Subject: [PATCH 102/202] Conversation: Rename function to better express what it does. --- lib/pleroma/conversation.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index fb0dfedca..be5821ad7 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -40,7 +40,7 @@ def get_for_ap_id(ap_id) do Repo.get_by(__MODULE__, ap_id: ap_id) end - def maybe_set_recipients(participation, activity) do + def maybe_create_recipientships(participation, activity) do participation = Repo.preload(participation, :recipients) if participation.recipients |> Enum.empty?() do @@ -70,7 +70,7 @@ def create_or_bump_for(activity, opts \\ []) do {:ok, participation} = Participation.create_for_user_and_conversation(user, conversation, opts) - maybe_set_recipients(participation, activity) + maybe_create_recipientships(participation, activity) participation end) From 139b196bc0328d812adb9434b2da97265d57257d Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 6 Aug 2019 20:19:28 +0000 Subject: [PATCH 103/202] [#1150] fixed parser TwitterCard --- .../web/rich_media/parsers/twitter_card.ex | 21 +- ...facial-recognition-children-teenagers.html | 227 ++++++++++++++++++ ...acial-recognition-children-teenagers2.html | 226 +++++++++++++++++ ...acial-recognition-children-teenagers3.html | 227 ++++++++++++++++++ .../rich_media/parsers/twitter_card_test.exs | 69 ++++++ 5 files changed, 763 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/nypd-facial-recognition-children-teenagers.html create mode 100644 test/fixtures/nypd-facial-recognition-children-teenagers2.html create mode 100644 test/fixtures/nypd-facial-recognition-children-teenagers3.html create mode 100644 test/web/rich_media/parsers/twitter_card_test.exs diff --git a/lib/pleroma/web/rich_media/parsers/twitter_card.ex b/lib/pleroma/web/rich_media/parsers/twitter_card.ex index e4efe2dd0..afaa98f3d 100644 --- a/lib/pleroma/web/rich_media/parsers/twitter_card.ex +++ b/lib/pleroma/web/rich_media/parsers/twitter_card.ex @@ -3,13 +3,20 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do + alias Pleroma.Web.RichMedia.Parsers.MetaTagsParser + + @spec parse(String.t(), map()) :: {:ok, map()} | {:error, String.t()} def parse(html, data) do - Pleroma.Web.RichMedia.Parsers.MetaTagsParser.parse( - html, - data, - "twitter", - "No twitter card metadata found", - "name" - ) + data + |> parse_name_attrs(html) + |> parse_property_attrs(html) + end + + defp parse_name_attrs(data, html) do + MetaTagsParser.parse(html, data, "twitter", %{}, "name") + end + + defp parse_property_attrs({_, data}, html) do + MetaTagsParser.parse(html, data, "twitter", "No twitter card metadata found", "property") end end diff --git a/test/fixtures/nypd-facial-recognition-children-teenagers.html b/test/fixtures/nypd-facial-recognition-children-teenagers.html new file mode 100644 index 000000000..5702c4484 --- /dev/null +++ b/test/fixtures/nypd-facial-recognition-children-teenagers.html @@ -0,0 +1,227 @@ + + + + She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database. - The New York Times + + + + + + + + + + + + + + + + + + + + + +

Advertisement

She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.

With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.

Image
CreditCreditSarah Blesener for The New York Times

[What you need to know to start the day: Get New York Today in your inbox.]

The New York Police Department has been loading thousands of arrest photos of children and teenagers into a facial recognition database despite evidence the technology has a higher risk of false matches in younger faces.

For about four years, internal records show, the department has used the technology to compare crime scene images with its collection of juvenile mug shots, the photos that are taken at an arrest. Most of the photos are of teenagers, largely 13 to 16 years old, but children as young as 11 have been included.

Elected officials and civil rights groups said the disclosure that the city was deploying a powerful surveillance tool on adolescents — whose privacy seems sacrosanct and whose status is protected in the criminal justice system — was a striking example of the Police Department’s ability to adopt advancing technology with little public scrutiny.

Several members of the City Council as well as a range of civil liberties groups said they were unaware of the policy until they were contacted by The New York Times.

Police Department officials defended the decision, saying it was just the latest evolution of a longstanding policing technique: using arrest photos to identify suspects.

“I don’t think this is any secret decision that’s made behind closed doors,” the city’s chief of detectives, Dermot F. Shea, said in an interview. “This is just process, and making sure we’re doing everything to fight crime.”

Other cities have begun to debate whether law enforcement should use facial recognition, which relies on an algorithm to quickly pore through images and suggest matches. In May, San Francisco blocked city agencies, including the police, from using the tool amid unease about potential government abuse. Detroit is facing public resistance to a technology that has been shown to have lower accuracy with people with darker skin.

In New York, the state Education Department recently told the Lockport, N.Y., school district to delay a plan to use facial recognition on students, citing privacy concerns.

“At the end of the day, it should be banned — no young people,” said Councilman Donovan Richards, a Queens Democrat who heads the Public Safety Committee, which oversees the Police Department.

The department said its legal bureau had approved using facial recognition on juveniles. The algorithm may suggest a lead, but detectives would not make an arrest based solely on that, Chief Shea said.

Image
CreditChang W. Lee/The New York Times

Still, facial recognition has not been widely tested on children. Most algorithms are taught to “think” based on adult faces, and there is growing evidence that they do not work as well on children.

The National Institute of Standards and Technology, which is part of the Commerce Department and evaluates facial recognition algorithms for accuracy, recently found the vast majority of more than 100 facial recognition algorithms had a higher rate of mistaken matches among children. The error rate was most pronounced in young children but was also seen in those aged 10 to 16.

Aging poses another problem: The appearance of children and adolescents can change drastically as bones stretch and shift, altering the underlying facial structure.

“I would use extreme caution in using those algorithms,” said Karl Ricanek Jr., a computer science professor and co-founder of the Face Aging Group at the University of North Carolina-Wilmington.

Technology that can match an image of a younger teenager to a recent arrest photo may be less effective at finding the same person even one or two years later, he said.

“The systems do not have the capacity to understand the dynamic changes that occur to a child’s face,” Dr. Ricanek said.

Idemia and DataWorks Plus, the two companies that provide facial recognition software to the Police Department, did not respond to requests for comment.

The New York Police Department can take arrest photos of minors as young as 11 who are charged with a felony, depending on the severity of the charge.

And in many cases, the department keeps the photos for years, making facial recognition comparisons to what may have effectively become outdated images. There are photos of 5,500 individuals in the juvenile database, 4,100 of whom are no longer 16 or under, the department said. Teenagers 17 and older are considered adults in the criminal justice system.

Police officials declined to provide statistics on how often their facial recognition systems provide false matches, or to explain how they evaluate the system’s effectiveness.

“We are comfortable with this technology because it has proved to be a valuable investigative method,” Chief Shea said. Facial recognition has helped lead to thousands of arrests of both adults and juveniles, the department has said.

Mayor Bill de Blasio had been aware the department was using the technology on minors, said Freddi Goldstein, a spokeswoman for the mayor.

She said the Police Department followed “strict guidelines” in applying the technology and City Hall monitored the agency’s compliance with the policies.

The Times learned details of the department’s use of facial recognition by reviewing documents posted online earlier this year by Clare Garvie, a senior associate at the Center on Privacy and Technology at Georgetown Law. Ms. Garvie received the documents as part of an open records lawsuit.

It could not be determined whether other large police departments used facial recognition with juveniles because very few have written policies governing the use of the technology, Ms. Garvie said.

New York detectives rely on a vast network of surveillance cameras throughout the city to provide images of people believed to have committed a crime. Since 2011, the department has had a dedicated unit of officers who use facial recognition to compare those images against millions of photos, usually mug shots. The software proposes matches, which have led to thousands of arrests, the department said.

By 2013, top police officials were meeting to discuss including juveniles in the program, the documents reviewed by The Times showed.

The documents showed that the juvenile database had been integrated into the system by 2015.

“We have these photos. It makes sense,” Chief Shea said in the interview.

State law requires that arrest photos be destroyed if the case is resolved in the juvenile’s favor, or if the child is found to have committed only a misdemeanor, rather than a felony. The photos also must be destroyed if a person reaches age 21 without a criminal record.

When children are charged with crimes, the court system usually takes some steps to prevent their acts from defining them in later years. Children who are 16 and under, for instance, are generally sent to Family Court, where records are not public.

Yet including their photos in a facial recognition database runs the risk that an imperfect algorithm identifies them as possible suspects in later crimes, civil rights advocates said. A mistaken match could lead investigators to focus on the wrong person from the outset, they said.

“It’s very disturbing to know that no matter what I’m doing at that moment, someone might be scanning my picture to try to find someone who committed a crime,” said Bailey, a 17-year-old Brooklyn girl who had admitted guilt in Family Court to a group attack that happened when she was 14. She said she was present at the attack but did not participate.

Bailey, who asked that she be identified only by her last name because she did not want her juvenile arrest to be public, has not been arrested again and is now a student at John Jay College of Criminal Justice.

Recent studies indicate that people of color, as well as children and women, have a greater risk of misidentification than their counterparts, said Joy Buolamwini, the founder of the Algorithmic Justice League and graduate researcher at the M.I.T. Media Lab, who has examined how human biases are built into artificial intelligence.

The racial disparities in the juvenile justice system are stark: In New York, black and Latino juveniles were charged with crimes at far higher rates than whites in 2017, the most recent year for which numbers were available. Black juveniles outnumbered white juveniles more than 15 to 1.

“If the facial recognition algorithm has a negative bias toward a black population, that will get magnified more toward children,” Dr. Ricanek said, adding that in terms of diminished accuracy, “you’re now putting yourself in unknown territory.”

Joseph Goldstein writes about policing and the criminal justice system. He has been a reporter at The Times since 2011, and is based in New York. He also worked for a year in the Kabul bureau, reporting on Afghanistan. @JoeKGoldstein

Ali Watkins is a reporter on the Metro Desk, covering courts and social services. Previously, she covered national security in Washington for The Times, BuzzFeed and McClatchy Newspapers. @AliWatkins

A version of this article appears in print on , Section A, Page 1 of the New York edition with the headline: In New York, Police Computers Scan Faces, Some as Young as 11. Order Reprints | Today’s Paper | Subscribe

Advertisement

+ + + + + + + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/test/fixtures/nypd-facial-recognition-children-teenagers2.html b/test/fixtures/nypd-facial-recognition-children-teenagers2.html new file mode 100644 index 000000000..ae8b26aff --- /dev/null +++ b/test/fixtures/nypd-facial-recognition-children-teenagers2.html @@ -0,0 +1,226 @@ + + + + She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database. - The New York Times + + + + + + + + + + + + + + + + + + + + +

Advertisement

She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.

With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.

Image
CreditCreditSarah Blesener for The New York Times

[What you need to know to start the day: Get New York Today in your inbox.]

The New York Police Department has been loading thousands of arrest photos of children and teenagers into a facial recognition database despite evidence the technology has a higher risk of false matches in younger faces.

For about four years, internal records show, the department has used the technology to compare crime scene images with its collection of juvenile mug shots, the photos that are taken at an arrest. Most of the photos are of teenagers, largely 13 to 16 years old, but children as young as 11 have been included.

Elected officials and civil rights groups said the disclosure that the city was deploying a powerful surveillance tool on adolescents — whose privacy seems sacrosanct and whose status is protected in the criminal justice system — was a striking example of the Police Department’s ability to adopt advancing technology with little public scrutiny.

Several members of the City Council as well as a range of civil liberties groups said they were unaware of the policy until they were contacted by The New York Times.

Police Department officials defended the decision, saying it was just the latest evolution of a longstanding policing technique: using arrest photos to identify suspects.

“I don’t think this is any secret decision that’s made behind closed doors,” the city’s chief of detectives, Dermot F. Shea, said in an interview. “This is just process, and making sure we’re doing everything to fight crime.”

Other cities have begun to debate whether law enforcement should use facial recognition, which relies on an algorithm to quickly pore through images and suggest matches. In May, San Francisco blocked city agencies, including the police, from using the tool amid unease about potential government abuse. Detroit is facing public resistance to a technology that has been shown to have lower accuracy with people with darker skin.

In New York, the state Education Department recently told the Lockport, N.Y., school district to delay a plan to use facial recognition on students, citing privacy concerns.

“At the end of the day, it should be banned — no young people,” said Councilman Donovan Richards, a Queens Democrat who heads the Public Safety Committee, which oversees the Police Department.

The department said its legal bureau had approved using facial recognition on juveniles. The algorithm may suggest a lead, but detectives would not make an arrest based solely on that, Chief Shea said.

Image
CreditChang W. Lee/The New York Times

Still, facial recognition has not been widely tested on children. Most algorithms are taught to “think” based on adult faces, and there is growing evidence that they do not work as well on children.

The National Institute of Standards and Technology, which is part of the Commerce Department and evaluates facial recognition algorithms for accuracy, recently found the vast majority of more than 100 facial recognition algorithms had a higher rate of mistaken matches among children. The error rate was most pronounced in young children but was also seen in those aged 10 to 16.

Aging poses another problem: The appearance of children and adolescents can change drastically as bones stretch and shift, altering the underlying facial structure.

“I would use extreme caution in using those algorithms,” said Karl Ricanek Jr., a computer science professor and co-founder of the Face Aging Group at the University of North Carolina-Wilmington.

Technology that can match an image of a younger teenager to a recent arrest photo may be less effective at finding the same person even one or two years later, he said.

“The systems do not have the capacity to understand the dynamic changes that occur to a child’s face,” Dr. Ricanek said.

Idemia and DataWorks Plus, the two companies that provide facial recognition software to the Police Department, did not respond to requests for comment.

The New York Police Department can take arrest photos of minors as young as 11 who are charged with a felony, depending on the severity of the charge.

And in many cases, the department keeps the photos for years, making facial recognition comparisons to what may have effectively become outdated images. There are photos of 5,500 individuals in the juvenile database, 4,100 of whom are no longer 16 or under, the department said. Teenagers 17 and older are considered adults in the criminal justice system.

Police officials declined to provide statistics on how often their facial recognition systems provide false matches, or to explain how they evaluate the system’s effectiveness.

“We are comfortable with this technology because it has proved to be a valuable investigative method,” Chief Shea said. Facial recognition has helped lead to thousands of arrests of both adults and juveniles, the department has said.

Mayor Bill de Blasio had been aware the department was using the technology on minors, said Freddi Goldstein, a spokeswoman for the mayor.

She said the Police Department followed “strict guidelines” in applying the technology and City Hall monitored the agency’s compliance with the policies.

The Times learned details of the department’s use of facial recognition by reviewing documents posted online earlier this year by Clare Garvie, a senior associate at the Center on Privacy and Technology at Georgetown Law. Ms. Garvie received the documents as part of an open records lawsuit.

It could not be determined whether other large police departments used facial recognition with juveniles because very few have written policies governing the use of the technology, Ms. Garvie said.

New York detectives rely on a vast network of surveillance cameras throughout the city to provide images of people believed to have committed a crime. Since 2011, the department has had a dedicated unit of officers who use facial recognition to compare those images against millions of photos, usually mug shots. The software proposes matches, which have led to thousands of arrests, the department said.

By 2013, top police officials were meeting to discuss including juveniles in the program, the documents reviewed by The Times showed.

The documents showed that the juvenile database had been integrated into the system by 2015.

“We have these photos. It makes sense,” Chief Shea said in the interview.

State law requires that arrest photos be destroyed if the case is resolved in the juvenile’s favor, or if the child is found to have committed only a misdemeanor, rather than a felony. The photos also must be destroyed if a person reaches age 21 without a criminal record.

When children are charged with crimes, the court system usually takes some steps to prevent their acts from defining them in later years. Children who are 16 and under, for instance, are generally sent to Family Court, where records are not public.

Yet including their photos in a facial recognition database runs the risk that an imperfect algorithm identifies them as possible suspects in later crimes, civil rights advocates said. A mistaken match could lead investigators to focus on the wrong person from the outset, they said.

“It’s very disturbing to know that no matter what I’m doing at that moment, someone might be scanning my picture to try to find someone who committed a crime,” said Bailey, a 17-year-old Brooklyn girl who had admitted guilt in Family Court to a group attack that happened when she was 14. She said she was present at the attack but did not participate.

Bailey, who asked that she be identified only by her last name because she did not want her juvenile arrest to be public, has not been arrested again and is now a student at John Jay College of Criminal Justice.

Recent studies indicate that people of color, as well as children and women, have a greater risk of misidentification than their counterparts, said Joy Buolamwini, the founder of the Algorithmic Justice League and graduate researcher at the M.I.T. Media Lab, who has examined how human biases are built into artificial intelligence.

The racial disparities in the juvenile justice system are stark: In New York, black and Latino juveniles were charged with crimes at far higher rates than whites in 2017, the most recent year for which numbers were available. Black juveniles outnumbered white juveniles more than 15 to 1.

“If the facial recognition algorithm has a negative bias toward a black population, that will get magnified more toward children,” Dr. Ricanek said, adding that in terms of diminished accuracy, “you’re now putting yourself in unknown territory.”

Joseph Goldstein writes about policing and the criminal justice system. He has been a reporter at The Times since 2011, and is based in New York. He also worked for a year in the Kabul bureau, reporting on Afghanistan. @JoeKGoldstein

Ali Watkins is a reporter on the Metro Desk, covering courts and social services. Previously, she covered national security in Washington for The Times, BuzzFeed and McClatchy Newspapers. @AliWatkins

A version of this article appears in print on , Section A, Page 1 of the New York edition with the headline: In New York, Police Computers Scan Faces, Some as Young as 11. Order Reprints | Today’s Paper | Subscribe

Advertisement

+ + + + + + + + + + +
+ +
+ + + + diff --git a/test/fixtures/nypd-facial-recognition-children-teenagers3.html b/test/fixtures/nypd-facial-recognition-children-teenagers3.html new file mode 100644 index 000000000..53454d23e --- /dev/null +++ b/test/fixtures/nypd-facial-recognition-children-teenagers3.html @@ -0,0 +1,227 @@ + + + + She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database. - The New York Times + + + + + + + + + + + + + + + + + + + + + +

Advertisement

She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.

With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.

Image
CreditCreditSarah Blesener for The New York Times

[What you need to know to start the day: Get New York Today in your inbox.]

The New York Police Department has been loading thousands of arrest photos of children and teenagers into a facial recognition database despite evidence the technology has a higher risk of false matches in younger faces.

For about four years, internal records show, the department has used the technology to compare crime scene images with its collection of juvenile mug shots, the photos that are taken at an arrest. Most of the photos are of teenagers, largely 13 to 16 years old, but children as young as 11 have been included.

Elected officials and civil rights groups said the disclosure that the city was deploying a powerful surveillance tool on adolescents — whose privacy seems sacrosanct and whose status is protected in the criminal justice system — was a striking example of the Police Department’s ability to adopt advancing technology with little public scrutiny.

Several members of the City Council as well as a range of civil liberties groups said they were unaware of the policy until they were contacted by The New York Times.

Police Department officials defended the decision, saying it was just the latest evolution of a longstanding policing technique: using arrest photos to identify suspects.

“I don’t think this is any secret decision that’s made behind closed doors,” the city’s chief of detectives, Dermot F. Shea, said in an interview. “This is just process, and making sure we’re doing everything to fight crime.”

Other cities have begun to debate whether law enforcement should use facial recognition, which relies on an algorithm to quickly pore through images and suggest matches. In May, San Francisco blocked city agencies, including the police, from using the tool amid unease about potential government abuse. Detroit is facing public resistance to a technology that has been shown to have lower accuracy with people with darker skin.

In New York, the state Education Department recently told the Lockport, N.Y., school district to delay a plan to use facial recognition on students, citing privacy concerns.

“At the end of the day, it should be banned — no young people,” said Councilman Donovan Richards, a Queens Democrat who heads the Public Safety Committee, which oversees the Police Department.

The department said its legal bureau had approved using facial recognition on juveniles. The algorithm may suggest a lead, but detectives would not make an arrest based solely on that, Chief Shea said.

Image
CreditChang W. Lee/The New York Times

Still, facial recognition has not been widely tested on children. Most algorithms are taught to “think” based on adult faces, and there is growing evidence that they do not work as well on children.

The National Institute of Standards and Technology, which is part of the Commerce Department and evaluates facial recognition algorithms for accuracy, recently found the vast majority of more than 100 facial recognition algorithms had a higher rate of mistaken matches among children. The error rate was most pronounced in young children but was also seen in those aged 10 to 16.

Aging poses another problem: The appearance of children and adolescents can change drastically as bones stretch and shift, altering the underlying facial structure.

“I would use extreme caution in using those algorithms,” said Karl Ricanek Jr., a computer science professor and co-founder of the Face Aging Group at the University of North Carolina-Wilmington.

Technology that can match an image of a younger teenager to a recent arrest photo may be less effective at finding the same person even one or two years later, he said.

“The systems do not have the capacity to understand the dynamic changes that occur to a child’s face,” Dr. Ricanek said.

Idemia and DataWorks Plus, the two companies that provide facial recognition software to the Police Department, did not respond to requests for comment.

The New York Police Department can take arrest photos of minors as young as 11 who are charged with a felony, depending on the severity of the charge.

And in many cases, the department keeps the photos for years, making facial recognition comparisons to what may have effectively become outdated images. There are photos of 5,500 individuals in the juvenile database, 4,100 of whom are no longer 16 or under, the department said. Teenagers 17 and older are considered adults in the criminal justice system.

Police officials declined to provide statistics on how often their facial recognition systems provide false matches, or to explain how they evaluate the system’s effectiveness.

“We are comfortable with this technology because it has proved to be a valuable investigative method,” Chief Shea said. Facial recognition has helped lead to thousands of arrests of both adults and juveniles, the department has said.

Mayor Bill de Blasio had been aware the department was using the technology on minors, said Freddi Goldstein, a spokeswoman for the mayor.

She said the Police Department followed “strict guidelines” in applying the technology and City Hall monitored the agency’s compliance with the policies.

The Times learned details of the department’s use of facial recognition by reviewing documents posted online earlier this year by Clare Garvie, a senior associate at the Center on Privacy and Technology at Georgetown Law. Ms. Garvie received the documents as part of an open records lawsuit.

It could not be determined whether other large police departments used facial recognition with juveniles because very few have written policies governing the use of the technology, Ms. Garvie said.

New York detectives rely on a vast network of surveillance cameras throughout the city to provide images of people believed to have committed a crime. Since 2011, the department has had a dedicated unit of officers who use facial recognition to compare those images against millions of photos, usually mug shots. The software proposes matches, which have led to thousands of arrests, the department said.

By 2013, top police officials were meeting to discuss including juveniles in the program, the documents reviewed by The Times showed.

The documents showed that the juvenile database had been integrated into the system by 2015.

“We have these photos. It makes sense,” Chief Shea said in the interview.

State law requires that arrest photos be destroyed if the case is resolved in the juvenile’s favor, or if the child is found to have committed only a misdemeanor, rather than a felony. The photos also must be destroyed if a person reaches age 21 without a criminal record.

When children are charged with crimes, the court system usually takes some steps to prevent their acts from defining them in later years. Children who are 16 and under, for instance, are generally sent to Family Court, where records are not public.

Yet including their photos in a facial recognition database runs the risk that an imperfect algorithm identifies them as possible suspects in later crimes, civil rights advocates said. A mistaken match could lead investigators to focus on the wrong person from the outset, they said.

“It’s very disturbing to know that no matter what I’m doing at that moment, someone might be scanning my picture to try to find someone who committed a crime,” said Bailey, a 17-year-old Brooklyn girl who had admitted guilt in Family Court to a group attack that happened when she was 14. She said she was present at the attack but did not participate.

Bailey, who asked that she be identified only by her last name because she did not want her juvenile arrest to be public, has not been arrested again and is now a student at John Jay College of Criminal Justice.

Recent studies indicate that people of color, as well as children and women, have a greater risk of misidentification than their counterparts, said Joy Buolamwini, the founder of the Algorithmic Justice League and graduate researcher at the M.I.T. Media Lab, who has examined how human biases are built into artificial intelligence.

The racial disparities in the juvenile justice system are stark: In New York, black and Latino juveniles were charged with crimes at far higher rates than whites in 2017, the most recent year for which numbers were available. Black juveniles outnumbered white juveniles more than 15 to 1.

“If the facial recognition algorithm has a negative bias toward a black population, that will get magnified more toward children,” Dr. Ricanek said, adding that in terms of diminished accuracy, “you’re now putting yourself in unknown territory.”

Joseph Goldstein writes about policing and the criminal justice system. He has been a reporter at The Times since 2011, and is based in New York. He also worked for a year in the Kabul bureau, reporting on Afghanistan. @JoeKGoldstein

Ali Watkins is a reporter on the Metro Desk, covering courts and social services. Previously, she covered national security in Washington for The Times, BuzzFeed and McClatchy Newspapers. @AliWatkins

A version of this article appears in print on , Section A, Page 1 of the New York edition with the headline: In New York, Police Computers Scan Faces, Some as Young as 11. Order Reprints | Today’s Paper | Subscribe

Advertisement

+ + + + + + + + + + +
+ +
+ + + + diff --git a/test/web/rich_media/parsers/twitter_card_test.exs b/test/web/rich_media/parsers/twitter_card_test.exs new file mode 100644 index 000000000..f8e1c9b40 --- /dev/null +++ b/test/web/rich_media/parsers/twitter_card_test.exs @@ -0,0 +1,69 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do + use ExUnit.Case, async: true + alias Pleroma.Web.RichMedia.Parsers.TwitterCard + + test "returns error when html not contains twitter card" do + assert TwitterCard.parse("", %{}) == {:error, "No twitter card metadata found"} + end + + test "parses twitter card with only name attributes" do + html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers3.html") + + assert TwitterCard.parse(html, %{}) == + {:ok, + %{ + "app:id:googleplay": "com.nytimes.android", + "app:name:googleplay": "NYTimes", + "app:url:googleplay": "nytimes://reader/id/100000006583622", + site: nil, + title: + "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database. - The New York Times" + }} + end + + test "parses twitter card with only property attributes" do + html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers2.html") + + assert TwitterCard.parse(html, %{}) == + {:ok, + %{ + card: "summary_large_image", + description: + "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", + image: + "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg", + "image:alt": "", + title: + "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.", + url: + "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html" + }} + end + + test "parses twitter card with name & property attributes" do + html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers.html") + + assert TwitterCard.parse(html, %{}) == + {:ok, + %{ + "app:id:googleplay": "com.nytimes.android", + "app:name:googleplay": "NYTimes", + "app:url:googleplay": "nytimes://reader/id/100000006583622", + card: "summary_large_image", + description: + "With little oversight, the N.Y.P.D. has been using powerful surveillance technology on photos of children and teenagers.", + image: + "https://static01.nyt.com/images/2019/08/01/nyregion/01nypd-juveniles-promo/01nypd-juveniles-promo-videoSixteenByNineJumbo1600.jpg", + "image:alt": "", + site: nil, + title: + "She Was Arrested at 14. Then Her Photo Went to a Facial Recognition Database.", + url: + "https://www.nytimes.com/2019/08/01/nyregion/nypd-facial-recognition-children-teenagers.html" + }} + end +end From 73d8d5c49f66d77ea77540223aaa8f94d91f63f8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 7 Aug 2019 00:12:42 +0300 Subject: [PATCH 104/202] Stop depending on the embedded object in restrict_favorited_by --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 2877c029e..1a279a7df 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -749,8 +749,8 @@ defp restrict_state(query, _), do: query defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do from( - activity in query, - where: fragment(~s(? <@ (? #> '{"object","likes"}'\)), ^ap_id, activity.data) + [_activity, object] in query, + where: fragment("(?)->'likes' \\? (?)", object.data, ^ap_id) ) end From 03ad31328c264a1154b7d3b5697b429452a1e6b0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 7 Aug 2019 00:23:58 +0300 Subject: [PATCH 105/202] OStatus Announce Representer: Do not depend on the object being embedded in the Create activity --- lib/pleroma/web/ostatus/activity_representer.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 760345301..8e55b9f0b 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -183,6 +183,7 @@ def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_autho author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] retweeted_activity = Activity.get_create_by_object_ap_id(activity.data["object"]) + retweeted_object = Object.normalize(retweeted_activity) retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"]) retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true) @@ -197,7 +198,7 @@ def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_autho {:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']}, {:id, h.(activity.data["id"])}, {:title, ['#{user.nickname} repeated a notice']}, - {:content, [type: 'html'], ['RT #{retweeted_activity.data["object"]["content"]}']}, + {:content, [type: 'html'], ['RT #{retweeted_object.data["content"]}']}, {:published, h.(inserted_at)}, {:updated, h.(updated_at)}, {:"ostatus:conversation", [ref: h.(activity.data["context"])], From 32018a4ee0fab43fc0982e6428d3fb93e5ac3c47 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 7 Aug 2019 00:36:13 +0300 Subject: [PATCH 106/202] ActivityPub tests: remove assertions of embedded object being updated, because the objects are no longer supposed to be embedded --- test/web/activity_pub/activity_pub_test.exs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 3d9a678dd..d723f331f 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -677,14 +677,8 @@ test "adds a like activity to the db" do assert object.data["likes"] == [user.ap_id] assert object.data["like_count"] == 1 - [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"]) - assert note_activity.data["object"]["like_count"] == 1 - {:ok, _like_activity, object} = ActivityPub.like(user_two, object) assert object.data["like_count"] == 2 - - [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"]) - assert note_activity.data["object"]["like_count"] == 2 end end From 5329e84d62bbdf87a4b66e2ba9302a840802416f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 7 Aug 2019 00:58:48 +0300 Subject: [PATCH 107/202] OStatus tests: stop relying on embedded objects --- test/web/ostatus/ostatus_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs index f8d389020..803a97695 100644 --- a/test/web/ostatus/ostatus_test.exs +++ b/test/web/ostatus/ostatus_test.exs @@ -199,7 +199,7 @@ test "handle incoming retweets - GS, subscription - local message" do assert retweeted_activity.data["type"] == "Create" assert retweeted_activity.data["actor"] == user.ap_id assert retweeted_activity.local - assert retweeted_activity.data["object"]["announcement_count"] == 1 + assert Object.normalize(retweeted_activity).data["announcement_count"] == 1 end test "handle incoming retweets - Mastodon, salmon" do From 4f1b9c54b9317863083bfb767b8e12c6b14cc14c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 7 Aug 2019 01:02:29 +0300 Subject: [PATCH 108/202] Do not rembed the object after updating it --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/utils.ex | 17 +---------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2713461ed..069974e44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - Not being able to pin unlisted posts +- Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised. - Metadata rendering errors resulting in the entire page being inaccessible - Federation/MediaProxy not working with instances that have wrong certificate order - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 39074888b..fc5305c58 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -251,20 +251,6 @@ def insert_full_object(%{"object" => %{"type" => type} = object_data} = map) def insert_full_object(map), do: {:ok, map, nil} - def update_object_in_activities(%{data: %{"id" => id}} = object) do - # TODO - # Update activities that already had this. Could be done in a seperate process. - # Alternatively, just don't do this and fetch the current object each time. Most - # could probably be taken from cache. - relevant_activities = Activity.get_all_create_by_object_ap_id(id) - - Enum.map(relevant_activities, fn activity -> - new_activity_data = activity.data |> Map.put("object", object.data) - changeset = Changeset.change(activity, data: new_activity_data) - Repo.update(changeset) - end) - end - #### Like-related helpers @doc """ @@ -347,8 +333,7 @@ def update_element_in_object(property, element, object) do |> Map.put("#{property}_count", length(element)) |> Map.put("#{property}s", element), changeset <- Changeset.change(object, data: new_data), - {:ok, object} <- Object.update_and_set_cache(changeset), - _ <- update_object_in_activities(object) do + {:ok, object} <- Object.update_and_set_cache(changeset) do {:ok, object} end end From a10c840abaeb8402051665412fbfd50e4a5ea054 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Wed, 7 Aug 2019 20:29:30 +0000 Subject: [PATCH 109/202] Return profile URL when available instead of actor URI for MastodonAPI mention URL Fixes #1165 --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index b2b06eeb9..3212dcbc3 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -28,7 +28,7 @@ def render("mention.json", %{user: user}) do id: to_string(user.id), acct: user.nickname, username: username_from_nickname(user.nickname), - url: user.ap_id + url: User.profile_url(user) || user.ap_id } end From 089d53a961f14681cf91c923eeb67478ec230da9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Wed, 7 Aug 2019 20:55:37 +0000 Subject: [PATCH 110/202] Simplify logic to mention.js `url` field `User.profile_url` already fallbacks to ap_id --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 3212dcbc3..82f8cd020 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -28,7 +28,7 @@ def render("mention.json", %{user: user}) do id: to_string(user.id), acct: user.nickname, username: username_from_nickname(user.nickname), - url: User.profile_url(user) || user.ap_id + url: User.profile_url(user) } end From 9c0da1009aa2100a206fae13f88ea9faddcd6bbd Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Wed, 7 Aug 2019 21:40:53 +0000 Subject: [PATCH 111/202] Return profile URL in MastodonAPI's `url` field --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 82f8cd020..de084fd6e 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -106,7 +106,7 @@ defp do_render("account.json", %{user: user} = opts) do following_count: user_info.following_count, statuses_count: user_info.note_count, note: bio || "", - url: user.ap_id, + url: User.profile_url(user), avatar: image, avatar_static: image, header: header, From 409bcad54b5de631536761952faed05ad5fe3b99 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 9 Aug 2019 16:49:09 +0300 Subject: [PATCH 112/202] Mastodon API: Set follower/following counters to 0 when hiding followers/following is enabled We are already doing that in AP representation, so I think we should do it here as well for consistency. --- CHANGELOG.md | 1 + .../web/mastodon_api/views/account_view.ex | 11 ++++++-- test/web/mastodon_api/account_view_test.exs | 27 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dccc36965..5d08fe757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Federation/MediaProxy not working with instances that have wrong certificate order - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`) - Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity +- Mastodon API: follower/following counters not being nullified, when `hide_follows`/`hide_followers` is set - Mastodon API: Add `account_id`, `type`, `offset`, and `limit` to search API (`/api/v1/search` and `/api/v2/search`) - Mastodon API, streaming: Fix filtering of notifications based on blocks/mutes/thread mutes - ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index de084fd6e..72c092f25 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -72,6 +72,13 @@ defp do_render("account.json", %{user: user} = opts) do image = User.avatar_url(user) |> MediaProxy.url() header = User.banner_url(user) |> MediaProxy.url() user_info = User.get_cached_user_info(user) + + following_count = + ((!user.info.hide_follows or opts[:for] == user) && user_info.following_count) || 0 + + followers_count = + ((!user.info.hide_followers or opts[:for] == user) && user_info.follower_count) || 0 + bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"] emojis = @@ -102,8 +109,8 @@ defp do_render("account.json", %{user: user} = opts) do display_name: display_name, locked: user_info.locked, created_at: Utils.to_masto_date(user.inserted_at), - followers_count: user_info.follower_count, - following_count: user_info.following_count, + followers_count: followers_count, + following_count: following_count, statuses_count: user_info.note_count, note: bio || "", url: User.profile_url(user), diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index 905e9af98..a26f514a5 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -356,4 +356,31 @@ test "sanitizes display names" do result = AccountView.render("account.json", %{user: user}) refute result.display_name == " username " end + + describe "hiding follows/following" do + test "shows when follows/following are hidden and sets follower/following count to 0" do + user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 0, + following_count: 0, + pleroma: %{hide_follows: true, hide_followers: true} + } = AccountView.render("account.json", %{user: user}) + end + + test "shows actual follower/following count to the account owner" do + user = insert(:user, info: %{hide_followers: true, hide_follows: true}) + other_user = insert(:user) + {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + + assert %{ + followers_count: 1, + following_count: 1 + } = AccountView.render("account.json", %{user: user, for: user}) + end + end end From dfae61c25c7ee2bb8add38b2cbaa8391f03c9550 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 9 Aug 2019 23:05:28 +0300 Subject: [PATCH 113/202] Fix deactivated user deletion --- lib/mix/tasks/pleroma/user.ex | 2 +- lib/pleroma/user.ex | 34 +++++++++---------- lib/pleroma/web/activity_pub/activity_pub.ex | 10 +++--- .../web/activity_pub/transmogrifier.ex | 2 +- .../web/admin_api/admin_api_controller.ex | 4 +-- .../web/ostatus/handlers/delete_handler.ex | 2 +- test/user_test.exs | 8 +++++ 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index a3f8bc945..f33d01429 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -176,7 +176,7 @@ def run(["rm", nickname]) do start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - User.perform(:delete, user) + User.perform(:delete, user, nil) shell_info("User #{nickname} deleted.") else _ -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7d18f099e..14057a0e4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1029,13 +1029,26 @@ def update_notification_settings(%User{} = user, settings \\ %{}) do |> update_and_set_cache() end + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:fetch_initial_posts, %User{} = user) do + pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) + + Enum.each( + # Insert all the posts in reverse order, so they're in the right order on the timeline + Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), + &Pleroma.Web.Federator.incoming_ap_doc/1 + ) + + {:ok, user} + end + @spec delete(User.t()) :: :ok - def delete(%User{} = user), - do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user]) + def delete(%User{} = user, actor \\ nil), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user, actor]) @spec perform(atom(), User.t()) :: {:ok, User.t()} - def perform(:delete, %User{} = user) do - {:ok, _user} = ActivityPub.delete(user) + def perform(:delete, %User{} = user, actor) do + {:ok, _user} = ActivityPub.delete(user, actor: actor) # Remove all relationships {:ok, followers} = User.get_followers(user) @@ -1057,19 +1070,6 @@ def perform(:delete, %User{} = user) do Repo.delete(user) end - @spec perform(atom(), User.t()) :: {:ok, User.t()} - def perform(:fetch_initial_posts, %User{} = user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - Enum.each( - # Insert all the posts in reverse order, so they're in the right order on the timeline - Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), - &Pleroma.Web.Federator.incoming_ap_doc/1 - ) - - {:ok, user} - end - def perform(:deactivate_async, user, status), do: deactivate(user, status) @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1a279a7df..8f669acb9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -403,11 +403,13 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do end end - def delete(%User{ap_id: ap_id, follower_address: follower_address} = user) do + def delete(data, opts \\ %{actor: nil, local: true}) + + def delete(%User{ap_id: ap_id, follower_address: follower_address} = user, opts) do with data <- %{ "to" => [follower_address], "type" => "Delete", - "actor" => ap_id, + "actor" => opts[:actor] || ap_id, "object" => %{"type" => "Person", "id" => ap_id} }, {:ok, activity} <- insert(data, true, true), @@ -416,7 +418,7 @@ def delete(%User{ap_id: ap_id, follower_address: follower_address} = user) do end end - def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do + def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, opts) do user = User.get_cached_by_ap_id(actor) to = (object.data["to"] || []) ++ (object.data["cc"] || []) @@ -428,7 +430,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru "to" => to, "deleted_activity_id" => activity && activity.id }, - {:ok, activity} <- insert(data, local, false), + {:ok, activity} <- insert(data, opts[:local], false), stream_out_participations(object, user), _ <- decrease_replies_count_if_reply(object), # Changing note count prior to enqueuing federation task in order to avoid diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5403b71d8..b34ef73c0 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -649,7 +649,7 @@ def handle_incoming( {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id), :ok <- Containment.contain_origin(actor.ap_id, object.data), - {:ok, activity} <- ActivityPub.delete(object, false) do + {:ok, activity} <- ActivityPub.delete(object, local: false) do {:ok, activity} else nil -> diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 2d3d0adc4..63c9a7d7f 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -25,9 +25,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do action_fallback(:errors) - def user_delete(conn, %{"nickname" => nickname}) do + def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do User.get_cached_by_nickname(nickname) - |> User.delete() + |> User.delete(admin.ap_id) conn |> json(nickname) diff --git a/lib/pleroma/web/ostatus/handlers/delete_handler.ex b/lib/pleroma/web/ostatus/handlers/delete_handler.ex index b2f9f3946..ac2dc115c 100644 --- a/lib/pleroma/web/ostatus/handlers/delete_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/delete_handler.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.OStatus.DeleteHandler do def handle_delete(entry, _doc \\ nil) do with id <- XML.string_from_xpath("//id", entry), %Object{} = object <- Object.normalize(id), - {:ok, delete} <- ActivityPub.delete(object, false) do + {:ok, delete} <- ActivityPub.delete(object, local: false) do delete end end diff --git a/test/user_test.exs b/test/user_test.exs index 8440d456d..e2da8d84b 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -998,6 +998,14 @@ test ".delete_user_activities deletes all create activities", %{user: user} do refute Activity.get_by_id(activity.id) end + test "it deletes deactivated user" do + admin = insert(:user, %{info: %{is_admin: true}}) + {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache() + + assert {:ok, _} = User.delete(user, admin.ap_id) + refute User.get_by_id(user.id) + end + test "it deletes a user, all follow relationships and all activities", %{user: user} do follower = insert(:user) {:ok, follower} = User.follow(follower, user) From bb9c53958038bb74ad76a9d887b15e6decb5249c Mon Sep 17 00:00:00 2001 From: Maksim Date: Sat, 10 Aug 2019 11:27:59 +0000 Subject: [PATCH 114/202] Uploader.S3 added support stream uploads --- lib/pleroma/uploaders/s3.ex | 12 ++--- mix.exs | 3 +- mix.lock | 1 + test/uploaders/s3_test.exs | 90 +++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 test/uploaders/s3_test.exs diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex index 521daa93b..8c353bed3 100644 --- a/lib/pleroma/uploaders/s3.ex +++ b/lib/pleroma/uploaders/s3.ex @@ -6,10 +6,12 @@ defmodule Pleroma.Uploaders.S3 do @behaviour Pleroma.Uploaders.Uploader require Logger + alias Pleroma.Config + # The file name is re-encoded with S3's constraints here to comply with previous # links with less strict filenames def get_file(file) do - config = Pleroma.Config.get([__MODULE__]) + config = Config.get([__MODULE__]) bucket = Keyword.fetch!(config, :bucket) bucket_with_namespace = @@ -34,15 +36,15 @@ def get_file(file) do end def put_file(%Pleroma.Upload{} = upload) do - config = Pleroma.Config.get([__MODULE__]) + config = Config.get([__MODULE__]) bucket = Keyword.get(config, :bucket) - {:ok, file_data} = File.read(upload.tempfile) - s3_name = strict_encode(upload.path) op = - ExAws.S3.put_object(bucket, s3_name, file_data, [ + upload.tempfile + |> ExAws.S3.Upload.stream_file() + |> ExAws.S3.upload(bucket, s3_name, [ {:acl, :public_read}, {:content_type, upload.content_type} ]) diff --git a/mix.exs b/mix.exs index ac175dfed..334fabb33 100644 --- a/mix.exs +++ b/mix.exs @@ -114,8 +114,9 @@ defp deps do {:tesla, "~> 1.2"}, {:jason, "~> 1.0"}, {:mogrify, "~> 0.6.1"}, - {:ex_aws, "~> 2.0"}, + {:ex_aws, "~> 2.1"}, {:ex_aws_s3, "~> 2.0"}, + {:sweet_xml, "~> 0.6.6"}, {:earmark, "~> 1.3"}, {:bbcode, "~> 0.1.1"}, {:ex_machina, "~> 2.3", only: :test}, diff --git a/mix.lock b/mix.lock index 13728d11f..f8ee80c83 100644 --- a/mix.lock +++ b/mix.lock @@ -80,6 +80,7 @@ "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, "swoosh": {:hex, :swoosh, "0.23.2", "7dda95ff0bf54a2298328d6899c74dae1223777b43563ccebebb4b5d2b61df38", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, diff --git a/test/uploaders/s3_test.exs b/test/uploaders/s3_test.exs new file mode 100644 index 000000000..a0a1cfdf0 --- /dev/null +++ b/test/uploaders/s3_test.exs @@ -0,0 +1,90 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Uploaders.S3Test do + use Pleroma.DataCase + + alias Pleroma.Config + alias Pleroma.Uploaders.S3 + + import Mock + import ExUnit.CaptureLog + + setup do + config = Config.get([Pleroma.Uploaders.S3]) + + Config.put([Pleroma.Uploaders.S3], + bucket: "test_bucket", + public_endpoint: "https://s3.amazonaws.com" + ) + + on_exit(fn -> + Config.put([Pleroma.Uploaders.S3], config) + end) + + :ok + end + + describe "get_file/1" do + test "it returns path to local folder for files" do + assert S3.get_file("test_image.jpg") == { + :ok, + {:url, "https://s3.amazonaws.com/test_bucket/test_image.jpg"} + } + end + + test "it returns path without bucket when truncated_namespace set to ''" do + Config.put([Pleroma.Uploaders.S3], + bucket: "test_bucket", + public_endpoint: "https://s3.amazonaws.com", + truncated_namespace: "" + ) + + assert S3.get_file("test_image.jpg") == { + :ok, + {:url, "https://s3.amazonaws.com/test_image.jpg"} + } + end + + test "it returns path with bucket namespace when namespace is set" do + Config.put([Pleroma.Uploaders.S3], + bucket: "test_bucket", + public_endpoint: "https://s3.amazonaws.com", + bucket_namespace: "family" + ) + + assert S3.get_file("test_image.jpg") == { + :ok, + {:url, "https://s3.amazonaws.com/family:test_bucket/test_image.jpg"} + } + end + end + + describe "put_file/1" do + setup do + file_upload = %Pleroma.Upload{ + name: "image-tet.jpg", + content_type: "image/jpg", + path: "test_folder/image-tet.jpg", + tempfile: Path.absname("test/fixtures/image_tmp.jpg") + } + + [file_upload: file_upload] + end + + test "save file", %{file_upload: file_upload} do + with_mock ExAws, request: fn _ -> {:ok, :ok} end do + assert S3.put_file(file_upload) == {:ok, {:file, "test_folder/image-tet.jpg"}} + end + end + + test "returns error", %{file_upload: file_upload} do + with_mock ExAws, request: fn _ -> {:error, "S3 Upload failed"} end do + assert capture_log(fn -> + assert S3.put_file(file_upload) == {:error, "S3 Upload failed"} + end) =~ "Elixir.Pleroma.Uploaders.S3: {:error, \"S3 Upload failed\"}" + end + end + end +end From 0802a08871afee7f09362cbca8b802f0e27ff4b9 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 10 Aug 2019 16:27:46 +0300 Subject: [PATCH 115/202] Mastodon API: Fix thread mute detection It was calling CommonAPI.thread_muted? with post author's account instead of viewer's one. --- CHANGELOG.md | 1 + lib/pleroma/web/mastodon_api/views/status_view.ex | 2 +- test/web/mastodon_api/mastodon_api_controller_test.exs | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dccc36965..31caef499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Federation/MediaProxy not working with instances that have wrong certificate order - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`) - Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity +- Mastodon API: `muted` in the Status entity, using author's account to determine if the tread was muted - Mastodon API: Add `account_id`, `type`, `offset`, and `limit` to search API (`/api/v1/search` and `/api/v2/search`) - Mastodon API, streaming: Fix filtering of notifications based on blocks/mutes/thread mutes - ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 80df9b2ac..02819e116 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -168,7 +168,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity thread_muted? = case activity.thread_muted? do thread_muted? when is_boolean(thread_muted?) -> thread_muted? - nil -> CommonAPI.thread_muted?(user, activity) + nil -> (opts[:for] && CommonAPI.thread_muted?(opts[:for], activity)) || false end attachment_data = object.data["attachment"] || [] diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index e49c4cc22..b023d1e4f 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2901,8 +2901,10 @@ test "bookmarks" do describe "conversation muting" do setup do + post_user = insert(:user) user = insert(:user) - {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"}) + + {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"}) [user: user, activity: activity] end From 11d08c2de0226caed8119bb3a45a8e0ab8791fbe Mon Sep 17 00:00:00 2001 From: Maksim Date: Sat, 10 Aug 2019 18:46:26 +0000 Subject: [PATCH 116/202] tests for Pleroma.Uploaders --- docs/config.md | 1 + lib/pleroma/uploaders/local.ex | 4 +-- lib/pleroma/uploaders/mdii.ex | 2 ++ test/uploaders/local_test.exs | 32 ++++++++++++++++++++++ test/uploaders/mdii_test.exs | 50 ++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/uploaders/local_test.exs create mode 100644 test/uploaders/mdii_test.exs diff --git a/docs/config.md b/docs/config.md index 703ef67dd..55311b76d 100644 --- a/docs/config.md +++ b/docs/config.md @@ -18,6 +18,7 @@ Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. ## Pleroma.Uploaders.S3 * `bucket`: S3 bucket name +* `bucket_namespace`: S3 bucket namespace * `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com") * `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc. For example, when using CDN to S3 virtual host format, set "". diff --git a/lib/pleroma/uploaders/local.ex b/lib/pleroma/uploaders/local.ex index fc533da23..36b3c35ec 100644 --- a/lib/pleroma/uploaders/local.ex +++ b/lib/pleroma/uploaders/local.ex @@ -11,7 +11,7 @@ def get_file(_) do def put_file(upload) do {local_path, file} = - case Enum.reverse(String.split(upload.path, "/", trim: true)) do + case Enum.reverse(Path.split(upload.path)) do [file] -> {upload_path(), file} @@ -23,7 +23,7 @@ def put_file(upload) do result_file = Path.join(local_path, file) - unless File.exists?(result_file) do + if not File.exists?(result_file) do File.cp!(upload.tempfile, result_file) end diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex index 237544337..c36f3d61d 100644 --- a/lib/pleroma/uploaders/mdii.ex +++ b/lib/pleroma/uploaders/mdii.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Uploaders.MDII do + @moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure" + alias Pleroma.Config alias Pleroma.HTTP diff --git a/test/uploaders/local_test.exs b/test/uploaders/local_test.exs new file mode 100644 index 000000000..fc442d0f1 --- /dev/null +++ b/test/uploaders/local_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Uploaders.LocalTest do + use Pleroma.DataCase + alias Pleroma.Uploaders.Local + + describe "get_file/1" do + test "it returns path to local folder for files" do + assert Local.get_file("") == {:ok, {:static_dir, "test/uploads"}} + end + end + + describe "put_file/1" do + test "put file to local folder" do + file_path = "local_upload/files/image.jpg" + + file = %Pleroma.Upload{ + name: "image.jpg", + content_type: "image/jpg", + path: file_path, + tempfile: Path.absname("test/fixtures/image_tmp.jpg") + } + + assert Local.put_file(file) == :ok + + assert Path.join([Local.upload_path(), file_path]) + |> File.exists?() + end + end +end diff --git a/test/uploaders/mdii_test.exs b/test/uploaders/mdii_test.exs new file mode 100644 index 000000000..d432d40f0 --- /dev/null +++ b/test/uploaders/mdii_test.exs @@ -0,0 +1,50 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Uploaders.MDIITest do + use Pleroma.DataCase + alias Pleroma.Uploaders.MDII + import Tesla.Mock + + describe "get_file/1" do + test "it returns path to local folder for files" do + assert MDII.get_file("") == {:ok, {:static_dir, "test/uploads"}} + end + end + + describe "put_file/1" do + setup do + file_upload = %Pleroma.Upload{ + name: "mdii-image.jpg", + content_type: "image/jpg", + path: "test_folder/mdii-image.jpg", + tempfile: Path.absname("test/fixtures/image_tmp.jpg") + } + + [file_upload: file_upload] + end + + test "save file", %{file_upload: file_upload} do + mock(fn + %{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} -> + %Tesla.Env{status: 200, body: "mdii-image"} + end) + + assert MDII.put_file(file_upload) == + {:ok, {:url, "https://mdii.sakura.ne.jp/mdii-image.jpg"}} + end + + test "save file to local if MDII isn`t available", %{file_upload: file_upload} do + mock(fn + %{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} -> + %Tesla.Env{status: 500} + end) + + assert MDII.put_file(file_upload) == :ok + + assert Path.join([Pleroma.Uploaders.Local.upload_path(), file_upload.path]) + |> File.exists?() + end + end +end From af4cf35e2096a6d1660271f6935b6b9ce77c6757 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Sat, 10 Aug 2019 18:47:40 +0000 Subject: [PATCH 117/202] Strip internal fields including likes from incoming and outgoing activities --- CHANGELOG.md | 2 ++ lib/mix/tasks/pleroma/database.ex | 36 +++++++++++++++++++ .../web/activity_pub/transmogrifier.ex | 34 ++---------------- test/tasks/database_test.exs | 36 +++++++++++++++++++ test/web/activity_pub/transmogrifier_test.exs | 30 +++++++++++----- 5 files changed, 98 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31caef499..759779034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Endpoint for fetching latest user's statuses - Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=` for resending account confirmation. - Relays: Added a task to list relay subscriptions. +- Mix Tasks: `mix pleroma.database fix_likes_collections` +- Federation: Remove `likes` from objects. ### Changed - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 8547a329a..bcc2052d6 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -36,6 +36,10 @@ defmodule Mix.Tasks.Pleroma.Database do ## Remove duplicated items from following and update followers count for all users mix pleroma.database update_users_following_followers_counts + + ## Fix the pre-existing "likes" collections for all objects + + mix pleroma.database fix_likes_collections """ def run(["remove_embedded_objects" | args]) do {options, [], []} = @@ -125,4 +129,36 @@ def run(["prune_objects" | args]) do ) end end + + def run(["fix_likes_collections"]) do + import Ecto.Query + + start_pleroma() + + from(object in Object, + where: fragment("(?)->>'likes' is not null", object.data), + select: %{id: object.id, likes: fragment("(?)->>'likes'", object.data)} + ) + |> Pleroma.RepoStreamer.chunk_stream(100) + |> Stream.each(fn objects -> + ids = + objects + |> Enum.filter(fn object -> object.likes |> Jason.decode!() |> is_map() end) + |> Enum.map(& &1.id) + + Object + |> where([object], object.id in ^ids) + |> update([object], + set: [ + data: + fragment( + "jsonb_set(?, '{likes}', '[]'::jsonb, true)", + object.data + ) + ] + ) + |> Repo.update_all([], timeout: :infinity) + end) + |> Stream.run() + end end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5403b71d8..b7bc48f0a 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -26,6 +26,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do """ def fix_object(object, options \\ []) do object + |> strip_internal_fields |> fix_actor |> fix_url |> fix_attachments @@ -34,7 +35,6 @@ def fix_object(object, options \\ []) do |> fix_emoji |> fix_tag |> fix_content_map - |> fix_likes |> fix_addressing |> fix_summary |> fix_type(options) @@ -151,20 +151,6 @@ def fix_actor(%{"attributedTo" => actor} = object) do |> Map.put("actor", Containment.get_actor(%{"actor" => actor})) end - # Check for standardisation - # This is what Peertube does - # curl -H 'Accept: application/activity+json' $likes | jq .totalItems - # Prismo returns only an integer (count) as "likes" - def fix_likes(%{"likes" => likes} = object) when not is_map(likes) do - object - |> Map.put("likes", []) - |> Map.put("like_count", 0) - end - - def fix_likes(object) do - object - end - def fix_in_reply_to(object, options \\ []) def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options) @@ -784,7 +770,6 @@ def prepare_object(object) do |> add_mention_tags |> add_emoji_tags |> add_attributed_to - |> add_likes |> prepare_attachments |> set_conversation |> set_reply_to_uri @@ -971,22 +956,6 @@ def add_attributed_to(object) do |> Map.put("attributedTo", attributed_to) end - def add_likes(%{"id" => id, "like_count" => likes} = object) do - likes = %{ - "id" => "#{id}/likes", - "first" => "#{id}/likes?page=1", - "type" => "OrderedCollection", - "totalItems" => likes - } - - object - |> Map.put("likes", likes) - end - - def add_likes(object) do - object - end - def prepare_attachments(object) do attachments = (object["attachment"] || []) @@ -1002,6 +971,7 @@ def prepare_attachments(object) do defp strip_internal_fields(object) do object |> Map.drop([ + "likes", "like_count", "announcements", "announcement_count", diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs index 579130b05..a8f25f500 100644 --- a/test/tasks/database_test.exs +++ b/test/tasks/database_test.exs @@ -3,8 +3,11 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Mix.Tasks.Pleroma.DatabaseTest do + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.CommonAPI + use Pleroma.DataCase import Pleroma.Factory @@ -46,4 +49,37 @@ test "following and followers count are updated" do assert user.info.follower_count == 0 end end + + describe "running fix_likes_collections" do + test "it turns OrderedCollection likes into empty arrays" do + [user, user2] = insert_pair(:user) + + {:ok, %{id: id, object: object}} = CommonAPI.post(user, %{"status" => "test"}) + {:ok, %{object: object2}} = CommonAPI.post(user, %{"status" => "test test"}) + + CommonAPI.favorite(id, user2) + + likes = %{ + "first" => + "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", + "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", + "totalItems" => 3, + "type" => "OrderedCollection" + } + + new_data = Map.put(object2.data, "likes", likes) + + object2 + |> Ecto.Changeset.change(%{data: new_data}) + |> Repo.update() + + assert length(Object.get_by_id(object.id).data["likes"]) == 1 + assert is_map(Object.get_by_id(object2.id).data["likes"]) + + assert :ok == Mix.Tasks.Pleroma.Database.run(["fix_likes_collections"]) + + assert length(Object.get_by_id(object.id).data["likes"]) == 1 + assert Enum.empty?(Object.get_by_id(object2.id).data["likes"]) + end + end end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index e7498e005..060b91e29 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -450,6 +450,27 @@ test "it ensures that address fields become lists" do assert !is_nil(data["cc"]) end + test "it strips internal likes" do + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + + likes = %{ + "first" => + "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", + "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", + "totalItems" => 3, + "type" => "OrderedCollection" + } + + object = Map.put(data["object"], "likes", likes) + data = Map.put(data, "object", object) + + {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data) + + refute Map.has_key?(object.data, "likes") + end + test "it works for incoming update activities" do data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() @@ -1061,14 +1082,7 @@ test "it strips internal fields of article" do assert is_nil(modified["object"]["announcements"]) assert is_nil(modified["object"]["announcement_count"]) assert is_nil(modified["object"]["context_id"]) - end - - test "it adds like collection to object" do - activity = insert(:note_activity) - {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) - - assert modified["object"]["likes"]["type"] == "OrderedCollection" - assert modified["object"]["likes"]["totalItems"] == 0 + assert is_nil(modified["object"]["likes"]) end test "the directMessage flag is present" do From 9cfc289594c1d2a1b53c99e3e72bba4b6dc615ca Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Sat, 10 Aug 2019 21:18:26 +0000 Subject: [PATCH 118/202] MRF: ensure that subdomain_match calls are case-insensitive --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/mrf.ex | 2 +- test/web/activity_pub/mrf/mrf_test.exs | 24 +++++++++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc73c8df..6f1a22359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. - Report email not being sent to admins when the reporter is a remote user +- MRF: ensure that subdomain_match calls are case-insensitive ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index dd204b21c..caa2a3231 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -28,7 +28,7 @@ defp get_policies(_), do: [] @spec subdomains_regex([String.t()]) :: [Regex.t()] def subdomains_regex(domains) when is_list(domains) do - for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$) + for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i end @spec subdomain_match?([Regex.t()], String.t()) :: boolean() diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/web/activity_pub/mrf/mrf_test.exs index a9cdf5317..1a888e18f 100644 --- a/test/web/activity_pub/mrf/mrf_test.exs +++ b/test/web/activity_pub/mrf/mrf_test.exs @@ -4,8 +4,8 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do test "subdomains_regex/1" do assert MRF.subdomains_regex(["unsafe.tld", "*.unsafe.tld"]) == [ - ~r/^unsafe.tld$/, - ~r/^(.*\.)*unsafe.tld$/ + ~r/^unsafe.tld$/i, + ~r/^(.*\.)*unsafe.tld$/i ] end @@ -13,7 +13,7 @@ test "subdomains_regex/1" do test "common domains" do regexes = MRF.subdomains_regex(["unsafe.tld", "unsafe2.tld"]) - assert regexes == [~r/^unsafe.tld$/, ~r/^unsafe2.tld$/] + assert regexes == [~r/^unsafe.tld$/i, ~r/^unsafe2.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "unsafe2.tld") @@ -24,7 +24,7 @@ test "common domains" do test "wildcard domains with one subdomain" do regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - assert regexes == [~r/^(.*\.)*unsafe.tld$/] + assert regexes == [~r/^(.*\.)*unsafe.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.unsafe.tld") @@ -35,12 +35,26 @@ test "wildcard domains with one subdomain" do test "wildcard domains with two subdomains" do regexes = MRF.subdomains_regex(["*.unsafe.tld"]) - assert regexes == [~r/^(.*\.)*unsafe.tld$/] + assert regexes == [~r/^(.*\.)*unsafe.tld$/i] assert MRF.subdomain_match?(regexes, "unsafe.tld") assert MRF.subdomain_match?(regexes, "sub.sub.unsafe.tld") refute MRF.subdomain_match?(regexes, "sub.anotherunsafe.tld") refute MRF.subdomain_match?(regexes, "sub.unsafe.tldanother") end + + test "matches are case-insensitive" do + regexes = MRF.subdomains_regex(["UnSafe.TLD", "UnSAFE2.Tld"]) + + assert regexes == [~r/^UnSafe.TLD$/i, ~r/^UnSAFE2.Tld$/i] + + assert MRF.subdomain_match?(regexes, "UNSAFE.TLD") + assert MRF.subdomain_match?(regexes, "UNSAFE2.TLD") + assert MRF.subdomain_match?(regexes, "unsafe.tld") + assert MRF.subdomain_match?(regexes, "unsafe2.tld") + + refute MRF.subdomain_match?(regexes, "EXAMPLE.COM") + refute MRF.subdomain_match?(regexes, "example.com") + end end end From 92479c6f4870f1ebe4f530db6e31ba960855e1fa Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 11 Aug 2019 22:49:55 +0300 Subject: [PATCH 119/202] Do not fetch the reply object in `fix_type` unless the object has the `name` key and use a depth limit when fetching it --- lib/pleroma/web/activity_pub/transmogrifier.ex | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b7bc48f0a..0aee9369f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -333,13 +333,15 @@ def fix_content_map(object), do: object def fix_type(object, options \\ []) - def fix_type(%{"inReplyTo" => reply_id} = object, options) when is_binary(reply_id) do + def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options) + when is_binary(reply_id) do reply = - if Federator.allowed_incoming_reply_depth?(options[:depth]) do - Object.normalize(reply_id, true) + with true <- Federator.allowed_incoming_reply_depth?(options[:depth]), + {:ok, object} <- get_obj_helper(reply_id, options) do + object end - if reply && (reply.data["type"] == "Question" and object["name"]) do + if reply && reply.data["type"] == "Question" do Map.put(object, "type", "Answer") else object From d4d31ffdc4ea1b7a1bb154dbf6a61a90b99c646e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 11 Aug 2019 23:19:20 +0300 Subject: [PATCH 120/202] Add a changelog entry for !1552 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f1a22359..f3338a5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Not being able to pin unlisted posts - Objects being re-embedded to activities after being updated (e.g faved/reposted). Running 'mix pleroma.database prune_objects' again is advised. - Metadata rendering errors resulting in the entire page being inaccessible +- `federation_incoming_replies_max_depth` option being ignored in certain cases - Federation/MediaProxy not working with instances that have wrong certificate order - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`) - Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity From 23c46f7e72701b773d87b825526450e5f4ec6322 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 12 Aug 2019 12:51:08 +0200 Subject: [PATCH 121/202] Conversations: Use 'recipients' for accounts in conversation view. According to gargron, this is the intended usage. --- .../web/mastodon_api/views/conversation_view.ex | 15 +++------------ test/web/mastodon_api/conversation_view_test.exs | 6 ------ .../pleroma_api/pleroma_api_controller_test.exs | 8 ++++---- 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 5adaecdb0..4a81f0248 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.StatusView def render("participation.json", %{participation: participation, user: user}) do - participation = Repo.preload(participation, conversation: :users, recipients: []) + participation = Repo.preload(participation, conversation: [], recipients: []) last_activity_id = with nil <- participation.last_activity_id do @@ -28,7 +28,7 @@ def render("participation.json", %{participation: participation, user: user}) do # Conversations return all users except the current user. users = - participation.conversation.users + participation.recipients |> Enum.reject(&(&1.id == user.id)) accounts = @@ -37,20 +37,11 @@ def render("participation.json", %{participation: participation, user: user}) do as: :user }) - recipients = - AccountView.render("accounts.json", %{ - users: participation.recipients, - as: :user - }) - %{ id: participation.id |> to_string(), accounts: accounts, unread: !participation.read, - last_status: last_status, - pleroma: %{ - recipients: recipients - } + last_status: last_status } end end diff --git a/test/web/mastodon_api/conversation_view_test.exs b/test/web/mastodon_api/conversation_view_test.exs index e32cde5a8..27f668d9f 100644 --- a/test/web/mastodon_api/conversation_view_test.exs +++ b/test/web/mastodon_api/conversation_view_test.exs @@ -30,11 +30,5 @@ test "represents a Mastodon Conversation entity" do assert [account] = conversation.accounts assert account.id == other_user.id - - assert recipients = conversation.pleroma.recipients - recipient_ids = recipients |> Enum.map(& &1.id) - - assert user.id in recipient_ids - assert other_user.id in recipient_ids end end diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs index 7c75fb229..56bc1572c 100644 --- a/test/web/pleroma_api/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/pleroma_api_controller_test.exs @@ -67,10 +67,10 @@ test "PATCH /api/v1/pleroma/conversations/:id", %{conn: conn} do assert result["id"] == participation.id |> to_string - assert recipients = result["pleroma"]["recipients"] - recipient_ids = Enum.map(recipients, & &1["id"]) + [participation] = Participation.for_user(user) + participation = Repo.preload(participation, :recipients) - assert user.id in recipient_ids - assert other_user.id in recipient_ids + assert user in participation.recipients + assert other_user in participation.recipients end end From 60231ec7bd0af993dc19f69a57b261b3b4167636 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 12 Aug 2019 13:58:04 +0200 Subject: [PATCH 122/202] Conversation: Add endpoint to get a conversation by id. --- docs/api/pleroma_api.md | 6 ++++++ .../web/pleroma_api/pleroma_api_controller.ex | 9 +++++++++ lib/pleroma/web/router.ex | 1 + .../pleroma_api_controller_test.exs | 18 ++++++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index 590f2a3fb..b134b31a8 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -340,6 +340,12 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa * Params: Like other timelines * Response: JSON, statuses (200 - healthy, 503 unhealthy). +## `GET /api/v1/pleroma/conversations/:id` +### The conversation with the given ID. +* Method `GET` +* Authentication: required +* Params: None +* Response: JSON, statuses (200 - healthy, 503 unhealthy). ## `PATCH /api/v1/pleroma/conversations/:id` ### Update a conversation. Used to change the set of recipients. diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 018564452..3175a99b1 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -13,6 +13,15 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.StatusView + def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do + with %Participation{} = participation <- Participation.get(participation_id), + true <- user.id == participation.user_id do + conn + |> put_view(ConversationView) + |> render("participation.json", %{participation: participation, user: user}) + end + end + def conversation_statuses( %{assigns: %{user: user}} = conn, %{"id" => participation_id} = params diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c835f06b4..f0b6a02e9 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -265,6 +265,7 @@ defmodule Pleroma.Web.Router do scope [] do pipe_through(:oauth_write) get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) + get("/conversations/:id", PleromaAPIController, :conversation) patch("/conversations/:id", PleromaAPIController, :update_conversation) end end diff --git a/test/web/pleroma_api/pleroma_api_controller_test.exs b/test/web/pleroma_api/pleroma_api_controller_test.exs index 56bc1572c..ed6b79727 100644 --- a/test/web/pleroma_api/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/pleroma_api_controller_test.exs @@ -11,6 +11,24 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do import Pleroma.Factory + test "/api/v1/pleroma/conversations/:id", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = + CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) + + [participation] = Participation.for_user(other_user) + + result = + conn + |> assign(:user, other_user) + |> get("/api/v1/pleroma/conversations/#{participation.id}") + |> json_response(200) + + assert result["id"] == participation.id |> to_string() + end + test "/api/v1/pleroma/conversations/:id/statuses", %{conn: conn} do user = insert(:user) other_user = insert(:user) From 511ccea5aa36b4b0098e49b409b335b0ce8f042e Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 12 Aug 2019 14:23:06 +0200 Subject: [PATCH 123/202] ConversationView: Align parameter names with other views. --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 ++-- lib/pleroma/web/mastodon_api/views/conversation_view.ex | 2 +- lib/pleroma/web/pleroma_api/pleroma_api_controller.ex | 4 ++-- lib/pleroma/web/streamer.ex | 2 +- test/web/mastodon_api/conversation_view_test.exs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0deeab2be..eb2351eb7 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1743,7 +1743,7 @@ def conversations(%{assigns: %{user: user}} = conn, params) do conversations = Enum.map(participations, fn participation -> - ConversationView.render("participation.json", %{participation: participation, user: user}) + ConversationView.render("participation.json", %{participation: participation, for: user}) end) conn @@ -1756,7 +1756,7 @@ def conversation_read(%{assigns: %{user: user}} = conn, %{"id" => participation_ Repo.get_by(Participation, id: participation_id, user_id: user.id), {:ok, participation} <- Participation.mark_as_read(participation) do participation_view = - ConversationView.render("participation.json", %{participation: participation, user: user}) + ConversationView.render("participation.json", %{participation: participation, for: user}) conn |> json(participation_view) diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index 4a81f0248..40acc07b3 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.StatusView - def render("participation.json", %{participation: participation, user: user}) do + def render("participation.json", %{participation: participation, for: user}) do participation = Repo.preload(participation, conversation: [], recipients: []) last_activity_id = diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 3175a99b1..b5c3d2728 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -18,7 +18,7 @@ def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) true <- user.id == participation.user_id do conn |> put_view(ConversationView) - |> render("participation.json", %{participation: participation, user: user}) + |> render("participation.json", %{participation: participation, for: user}) end end @@ -69,7 +69,7 @@ def update_conversation( {:ok, _} <- Participation.set_recipients(participation, recipients) do conn |> put_view(ConversationView) - |> render("participation.json", %{participation: participation, user: user}) + |> render("participation.json", %{participation: participation, for: user}) end end end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 9ee331030..a0bb10895 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -209,7 +209,7 @@ def represent_conversation(%Participation{} = participation) do payload: Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ participation: participation, - user: participation.user + for: participation.user }) |> Jason.encode!() } diff --git a/test/web/mastodon_api/conversation_view_test.exs b/test/web/mastodon_api/conversation_view_test.exs index 27f668d9f..a2a880705 100644 --- a/test/web/mastodon_api/conversation_view_test.exs +++ b/test/web/mastodon_api/conversation_view_test.exs @@ -23,7 +23,7 @@ test "represents a Mastodon Conversation entity" do assert participation conversation = - ConversationView.render("participation.json", %{participation: participation, user: user}) + ConversationView.render("participation.json", %{participation: participation, for: user}) assert conversation.id == participation.id |> to_string() assert conversation.last_status.id == activity.id From 2674db14a2ee29e98265c0c0b1db412835b6bbed Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 12 Aug 2019 14:26:18 +0200 Subject: [PATCH 124/202] Modify Changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 069974e44..f8c90a73b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Report email not being sent to admins when the reporter is a remote user ### Added +- Conversations: Add Pleroma-specific conversation endpoints and status posting extensions. Run the `bump_all_conversations` task again to create the necessary data. - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) - MRF: Support for excluding specific domains from Transparency. - MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`) From 24a731a9a67a719749c99ca925f4adb2973a3f2d Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 12 Aug 2019 15:00:03 -0500 Subject: [PATCH 125/202] Update AdminFE Now permits server configuration. Consider this ALPHA. --- priv/static/adminfe/chunk-0e18.e12401fb.css | 1 + ...9.c27dac5e.css => chunk-1fbf.d7a1893c.css} | 2 +- ...8.0d22684d.css => chunk-2325.0d22684d.css} | 0 priv/static/adminfe/chunk-5e57.ac97b15a.css | 1 + ...f.1a04e979.css => chunk-e547.e4b6230b.css} | 2 +- .../adminfe/chunk-elementUI.e5cd8da6.css | 1 + .../adminfe/chunk-elementUI.f74c256b.css | 1 - priv/static/adminfe/index.html | 2 +- .../static/fonts/element-icons.2fad952.woff | Bin 6164 -> 0 bytes .../static/fonts/element-icons.535877f.woff | Bin 0 -> 28200 bytes .../static/fonts/element-icons.6f0a763.ttf | Bin 11040 -> 0 bytes .../static/fonts/element-icons.732389d.ttf | Bin 0 -> 55956 bytes priv/static/adminfe/static/js/app.4137ad8f.js | Bin 115467 -> 0 bytes priv/static/adminfe/static/js/app.8e186193.js | Bin 0 -> 137815 bytes .../adminfe/static/js/chunk-0e18.208cd826.js | Bin 0 -> 4774 bytes .../adminfe/static/js/chunk-1fbf.616fb309.js | Bin 0 -> 17717 bytes ...018.e1a7a454.js => chunk-2325.154a537b.js} | Bin 8220 -> 8220 bytes .../adminfe/static/js/chunk-56c9.28e35fc3.js | Bin 14105 -> 0 bytes .../adminfe/static/js/chunk-5e57.7313703a.js | Bin 0 -> 217441 bytes .../adminfe/static/js/chunk-5eaf.5b76e416.js | Bin 23071 -> 0 bytes .../adminfe/static/js/chunk-7fe2.458f9da5.js | Bin 0 -> 408401 bytes .../adminfe/static/js/chunk-e547.d57d1b91.js | Bin 0 -> 23125 bytes .../static/js/chunk-elementUI.1911151b.js | Bin 0 -> 638883 bytes .../static/js/chunk-elementUI.1fa5434b.js | Bin 562077 -> 0 bytes ...ibs.d5609760.js => chunk-libs.fb0b7f4a.js} | Bin 204098 -> 204635 bytes .../adminfe/static/js/runtime.d8d12c12.js | Bin 3434 -> 0 bytes .../adminfe/static/js/runtime.f40c8ec4.js | Bin 0 -> 3608 bytes 27 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 priv/static/adminfe/chunk-0e18.e12401fb.css rename priv/static/adminfe/{chunk-56c9.c27dac5e.css => chunk-1fbf.d7a1893c.css} (95%) rename priv/static/adminfe/{chunk-f018.0d22684d.css => chunk-2325.0d22684d.css} (100%) create mode 100644 priv/static/adminfe/chunk-5e57.ac97b15a.css rename priv/static/adminfe/{chunk-5eaf.1a04e979.css => chunk-e547.e4b6230b.css} (60%) create mode 100644 priv/static/adminfe/chunk-elementUI.e5cd8da6.css delete mode 100644 priv/static/adminfe/chunk-elementUI.f74c256b.css delete mode 100644 priv/static/adminfe/static/fonts/element-icons.2fad952.woff create mode 100644 priv/static/adminfe/static/fonts/element-icons.535877f.woff delete mode 100644 priv/static/adminfe/static/fonts/element-icons.6f0a763.ttf create mode 100644 priv/static/adminfe/static/fonts/element-icons.732389d.ttf delete mode 100644 priv/static/adminfe/static/js/app.4137ad8f.js create mode 100644 priv/static/adminfe/static/js/app.8e186193.js create mode 100644 priv/static/adminfe/static/js/chunk-0e18.208cd826.js create mode 100644 priv/static/adminfe/static/js/chunk-1fbf.616fb309.js rename priv/static/adminfe/static/js/{chunk-f018.e1a7a454.js => chunk-2325.154a537b.js} (98%) delete mode 100644 priv/static/adminfe/static/js/chunk-56c9.28e35fc3.js create mode 100644 priv/static/adminfe/static/js/chunk-5e57.7313703a.js delete mode 100644 priv/static/adminfe/static/js/chunk-5eaf.5b76e416.js create mode 100644 priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js create mode 100644 priv/static/adminfe/static/js/chunk-e547.d57d1b91.js create mode 100644 priv/static/adminfe/static/js/chunk-elementUI.1911151b.js delete mode 100644 priv/static/adminfe/static/js/chunk-elementUI.1fa5434b.js rename priv/static/adminfe/static/js/{chunk-libs.d5609760.js => chunk-libs.fb0b7f4a.js} (71%) delete mode 100644 priv/static/adminfe/static/js/runtime.d8d12c12.js create mode 100644 priv/static/adminfe/static/js/runtime.f40c8ec4.js diff --git a/priv/static/adminfe/chunk-0e18.e12401fb.css b/priv/static/adminfe/chunk-0e18.e12401fb.css new file mode 100644 index 000000000..ba85e77d5 --- /dev/null +++ b/priv/static/adminfe/chunk-0e18.e12401fb.css @@ -0,0 +1 @@ +header[data-v-71c7ded0]{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;margin:22px 0;padding-left:15px}header h1[data-v-71c7ded0]{margin:0 0 0 10px}table[data-v-71c7ded0]{margin:10px 0 0 15px}table .name-col[data-v-71c7ded0]{width:150px}.el-table--border[data-v-71c7ded0]:after,.el-table--group[data-v-71c7ded0]:after,.el-table[data-v-71c7ded0]:before{background-color:transparent}.poll ul[data-v-71c7ded0]{list-style-type:none;padding:0;width:30%}.image[data-v-71c7ded0]{width:20%}.image img[data-v-71c7ded0]{width:100%}.statuses[data-v-71c7ded0]{padding-right:20px}.show-private[data-v-71c7ded0]{text-align:right;line-height:67px;padding-right:20px} \ No newline at end of file diff --git a/priv/static/adminfe/chunk-56c9.c27dac5e.css b/priv/static/adminfe/chunk-1fbf.d7a1893c.css similarity index 95% rename from priv/static/adminfe/chunk-56c9.c27dac5e.css rename to priv/static/adminfe/chunk-1fbf.d7a1893c.css index 2b4283ec5..4672a9f75 100644 --- a/priv/static/adminfe/chunk-56c9.c27dac5e.css +++ b/priv/static/adminfe/chunk-1fbf.d7a1893c.css @@ -1 +1 @@ -.status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-avatar-img{width:15px;height:15px;margin-right:5px}.status-account-name{margin:0;height:22px}.status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-content{font-size:15px}.status-card{margin-bottom:15px}.status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.account{text-decoration:underline}.avatar-img{vertical-align:bottom;width:15px;height:15px;margin-left:5px}.el-card__body{padding:17px}.el-card__header{background-color:#fafafa;padding:10px 20px}.el-collapse{border-bottom:none}.el-collapse-item__header{height:46px;font-size:14px}.el-collapse-item__content{padding-bottom:7px}.el-icon-arrow-right{margin-right:6px}.el-icon-close{padding:10px 5px 10px 10px;cursor:pointer}h4{margin:0;height:17px}.header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;height:40px}.id{color:grey;margin-top:6px}.line{width:100%;height:0;border:.5px solid #ebeef5;margin:15px 0}.new-note p{font-size:14px;font-weight:500;height:17px;margin:13px 0 7px}.note{-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.1);box-shadow:0 2px 5px 0 rgba(0,0,0,.1);margin-bottom:10px}.no-notes{font-style:italic;color:grey}.report-row-key{font-weight:500;font-size:14px}.report-title{margin:0}.statuses{margin-top:15px}.submit-button{display:block;margin:7px 0 17px auto}.timestamp{margin:0;font-style:italic;color:grey}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.timeline-item-container .header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:80px}.timeline-item-container .id{margin:6px 0 0}}.select-field[data-v-bb4390da]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-bb4390da]{width:100%;margin-bottom:5px}}.reports-container .el-timeline[data-v-e32c7dc6]{margin:45px 45px 45px 19px;padding:0}.reports-container .filter-container[data-v-e32c7dc6]{margin:22px 15px;padding-bottom:0}.reports-container h1[data-v-e32c7dc6]{margin:22px 0 0 15px}.reports-container .no-reports-message[data-v-e32c7dc6]{color:grey;margin-left:19px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.reports-container h1[data-v-e32c7dc6]{margin:7px 10px 15px}.reports-container .filter-container[data-v-e32c7dc6]{margin:0 10px}.reports-container .timeline[data-v-e32c7dc6]{margin:20px 20px 20px 18px}} \ No newline at end of file +.status-account{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.status-avatar-img{width:15px;height:15px;margin-right:5px}.status-account-name{margin:0;height:22px}.status-body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.status-content{font-size:15px}.status-card{margin-bottom:15px}.status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-message{min-width:80%}.el-message-box{width:80%}.status-card .el-card__header{padding:10px 17px}.status-card .el-tag{margin:3px 4px 3px 0}.status-card .status-account-container{margin-bottom:5px}.status-card .status-actions-button{margin:3px 0}.status-card .status-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-card .status-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.account{text-decoration:underline}.avatar-img{vertical-align:bottom;width:15px;height:15px;margin-left:5px}.el-card__body{padding:17px}.el-card__header{background-color:#fafafa;padding:10px 20px}.el-collapse{border-bottom:none}.el-collapse-item__header{height:46px;font-size:14px}.el-collapse-item__content{padding-bottom:7px}.el-icon-arrow-right{margin-right:6px}.el-icon-close{padding:10px 5px 10px 10px;cursor:pointer}h4{margin:0;height:17px}.header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;height:40px}.id{color:grey;margin-top:6px}.line{width:100%;height:0;border:.5px solid #ebeef5;margin:15px 0}.new-note p{font-size:14px;font-weight:500;height:17px;margin:13px 0 7px}.note{-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.1);box-shadow:0 2px 5px 0 rgba(0,0,0,.1);margin-bottom:10px}.no-notes{font-style:italic;color:grey}.report-row-key{font-weight:500;font-size:14px}.report-title{margin:0}.statuses{margin-top:15px}.submit-button{display:block;margin:7px 0 17px auto}.timestamp{margin:0;font-style:italic;color:grey}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.timeline-item-container .header-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:80px}.timeline-item-container .id{margin:6px 0 0}}.select-field[data-v-07695bc4]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-07695bc4]{width:100%;margin-bottom:5px}}.reports-container .el-timeline[data-v-e32c7dc6]{margin:45px 45px 45px 19px;padding:0}.reports-container .filter-container[data-v-e32c7dc6]{margin:22px 15px;padding-bottom:0}.reports-container h1[data-v-e32c7dc6]{margin:22px 0 0 15px}.reports-container .no-reports-message[data-v-e32c7dc6]{color:grey;margin-left:19px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.reports-container h1[data-v-e32c7dc6]{margin:7px 10px 15px}.reports-container .filter-container[data-v-e32c7dc6]{margin:0 10px}.reports-container .timeline[data-v-e32c7dc6]{margin:20px 20px 20px 18px}} \ No newline at end of file diff --git a/priv/static/adminfe/chunk-f018.0d22684d.css b/priv/static/adminfe/chunk-2325.0d22684d.css similarity index 100% rename from priv/static/adminfe/chunk-f018.0d22684d.css rename to priv/static/adminfe/chunk-2325.0d22684d.css diff --git a/priv/static/adminfe/chunk-5e57.ac97b15a.css b/priv/static/adminfe/chunk-5e57.ac97b15a.css new file mode 100644 index 000000000..0c9284744 --- /dev/null +++ b/priv/static/adminfe/chunk-5e57.ac97b15a.css @@ -0,0 +1 @@ +a{text-decoration:underline}.code{background-color:rgba(173,190,214,.48);border-radius:3px;font-family:monospace;padding:0 3px}.el-form-item{margin-right:30px}.el-select{width:100%}.esshd-list{margin:0}.expl{color:#666;font-size:13px;line-height:22px;margin:5px 0 0;overflow-wrap:break-word}.highlight{background-color:#e6e6e6}.limit-button-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.limit-expl{margin-left:10px}.limit-input{width:48%;margin:0 0 5px 8px}.line{width:100%;height:0;border:1px solid #eee;margin-bottom:22px}.mascot-container{margin-bottom:15px}.mascot-input{margin-bottom:7px}.mascot-name-container{display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:7px}.mascot-name-input{margin-right:10px}.name-input{width:30%;margin-right:8px}.options-paragraph{font-size:14px;color:#606266;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei;font-weight:700;line-height:20px;margin:0 0 14px}.options-paragraph-container{overflow-wrap:break-word;margin-bottom:0}.pattern-input{width:20%;margin-right:8px}.setting-input{display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:10px}.single-input{margin-right:10px}.scale-input{width:48%;margin:0 8px 5px 0}.replacement-input{width:80%;margin-left:8px;margin-right:10px}.text{line-height:20px;margin-right:15px}.upload-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.value-input{width:70%;margin-left:8px;margin-right:10px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.el-form-item{margin-right:15px}.el-input__inner{padding:0 5px}.el-form-item__label:not(.no-top-margin){padding-left:3px;padding-right:10px;line-height:22px;margin-top:7px}.el-message{min-width:80%}.el-select__tags{overflow:hidden}.name-input{width:40%;margin-right:5px}p.expl{line-height:20px}.pattern-input{width:40%;margin-right:4px}.replacement-input{width:60%;margin-left:4px;margin-right:5px}.top-margin{position:absolute;top:25%}.value-input{width:60%;margin-left:5px;margin-right:8px}}.settings-container .el-tabs[data-v-729534ce]{margin-top:20px}.settings-container h1[data-v-729534ce]{margin:22px 0 0 15px} \ No newline at end of file diff --git a/priv/static/adminfe/chunk-5eaf.1a04e979.css b/priv/static/adminfe/chunk-e547.e4b6230b.css similarity index 60% rename from priv/static/adminfe/chunk-5eaf.1a04e979.css rename to priv/static/adminfe/chunk-e547.e4b6230b.css index a09287f58..f740543a0 100644 --- a/priv/static/adminfe/chunk-5eaf.1a04e979.css +++ b/priv/static/adminfe/chunk-e547.e4b6230b.css @@ -1 +1 @@ -.select-field[data-v-71bc6b38]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-71bc6b38]{width:100%;margin-bottom:5px}}.actions-button[data-v-94227b1e]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-94227b1e]{float:right}.el-icon-edit[data-v-94227b1e]{margin-right:5px}.tag-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-94227b1e]{padding-right:20px}.no-hover[data-v-94227b1e]:hover{color:#606266;background-color:#fff;cursor:auto}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.create-user-dialog{width:80%}.create-account-form-item{margin-bottom:30px}.el-dialog__body{padding:20px 20px 0}}.actions-button[data-v-3ffddd00]{text-align:left;width:350px;padding:10px}.actions-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0 15px 10px}.active-tag[data-v-3ffddd00]{color:#409eff;font-weight:700}.active-tag .el-icon-check[data-v-3ffddd00]{color:#409eff;float:right;margin:7px 0 0 15px}.el-dropdown-link[data-v-3ffddd00]:hover{cursor:pointer;color:#409eff}.el-icon-plus[data-v-3ffddd00]{margin-right:5px}.users-container h1[data-v-3ffddd00]{margin:22px 0 0 15px}.users-container .pagination[data-v-3ffddd00]{margin:25px 0;text-align:center}.users-container .search[data-v-3ffddd00]{width:350px;float:right}.users-container .filter-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 15px 15px}.users-container .user-count[data-v-3ffddd00]{color:grey;font-size:28px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.users-container h1[data-v-3ffddd00]{margin:7px 10px 15px}.users-container .actions-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px 7px}.users-container .create-account[data-v-3ffddd00]{width:100%}.users-container .el-icon-arrow-down[data-v-3ffddd00]{font-size:12px}.users-container .search[data-v-3ffddd00]{width:100%}.users-container .filter-container[data-v-3ffddd00]{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px}.users-container .el-tag[data-v-3ffddd00]{width:30px;display:inline-block;margin-bottom:4px;font-weight:700}.users-container .el-tag.el-tag--danger[data-v-3ffddd00],.users-container .el-tag.el-tag--success[data-v-3ffddd00]{padding-left:8px}} \ No newline at end of file +.select-field[data-v-71bc6b38]{width:350px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.select-field[data-v-71bc6b38]{width:100%;margin-bottom:5px}}.actions-button[data-v-94227b1e]{text-align:left;width:350px;padding:10px}.actions-button-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-dropdown[data-v-94227b1e]{float:right}.el-icon-edit[data-v-94227b1e]{margin-right:5px}.tag-container[data-v-94227b1e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.tag-text[data-v-94227b1e]{padding-right:20px}.no-hover[data-v-94227b1e]:hover{color:#606266;background-color:#fff;cursor:auto}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.create-user-dialog{width:80%}.create-account-form-item{margin-bottom:30px}.el-dialog__body{padding:20px 20px 0}}.actions-button[data-v-c51cd8ee]{text-align:left;width:350px;padding:10px}.actions-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0 15px 10px}.active-tag[data-v-c51cd8ee]{color:#409eff;font-weight:700}.active-tag .el-icon-check[data-v-c51cd8ee]{color:#409eff;float:right;margin:7px 0 0 15px}.el-dropdown-link[data-v-c51cd8ee]:hover{cursor:pointer;color:#409eff}.el-icon-plus[data-v-c51cd8ee]{margin-right:5px}.users-container h1[data-v-c51cd8ee]{margin:22px 0 0 15px}.users-container .pagination[data-v-c51cd8ee]{margin:25px 0;text-align:center}.users-container .search[data-v-c51cd8ee]{width:350px;float:right}.users-container .filter-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:36px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:22px 15px 15px}.users-container .user-count[data-v-c51cd8ee]{color:grey;font-size:28px}@media (min-device-width:768px) and (max-device-width:1024px),only screen and (max-width:760px){.users-container h1[data-v-c51cd8ee]{margin:7px 10px 15px}.users-container .actions-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px 7px}.users-container .create-account[data-v-c51cd8ee]{width:100%}.users-container .el-icon-arrow-down[data-v-c51cd8ee]{font-size:12px}.users-container .search[data-v-c51cd8ee]{width:100%}.users-container .filter-container[data-v-c51cd8ee]{display:-webkit-box;display:-ms-flexbox;display:flex;height:82px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:0 10px}.users-container .el-tag[data-v-c51cd8ee]{width:30px;display:inline-block;margin-bottom:4px;font-weight:700}.users-container .el-tag.el-tag--danger[data-v-c51cd8ee],.users-container .el-tag.el-tag--success[data-v-c51cd8ee]{padding-left:8px}} \ No newline at end of file diff --git a/priv/static/adminfe/chunk-elementUI.e5cd8da6.css b/priv/static/adminfe/chunk-elementUI.e5cd8da6.css new file mode 100644 index 000000000..3fef5e5fd --- /dev/null +++ b/priv/static/adminfe/chunk-elementUI.e5cd8da6.css @@ -0,0 +1 @@ +.el-pager,.el-table th{-moz-user-select:none;-ms-user-select:none}.el-pagination--small .arrow.disabled,.el-table--hidden,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(static/fonts/element-icons.535877f.woff) format("woff"),url(static/fonts/element-icons.732389d.ttf) format("truetype");font-weight:400;font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\E6A0"}.el-icon-ice-cream-square:before{content:"\E6A3"}.el-icon-lollipop:before{content:"\E6A4"}.el-icon-potato-strips:before{content:"\E6A5"}.el-icon-milk-tea:before{content:"\E6A6"}.el-icon-ice-drink:before{content:"\E6A7"}.el-icon-ice-tea:before{content:"\E6A9"}.el-icon-coffee:before{content:"\E6AA"}.el-icon-orange:before{content:"\E6AB"}.el-icon-pear:before{content:"\E6AC"}.el-icon-apple:before{content:"\E6AD"}.el-icon-cherry:before{content:"\E6AE"}.el-icon-watermelon:before{content:"\E6AF"}.el-icon-grape:before{content:"\E6B0"}.el-icon-refrigerator:before{content:"\E6B1"}.el-icon-goblet-square-full:before{content:"\E6B2"}.el-icon-goblet-square:before{content:"\E6B3"}.el-icon-goblet-full:before{content:"\E6B4"}.el-icon-goblet:before{content:"\E6B5"}.el-icon-cold-drink:before{content:"\E6B6"}.el-icon-coffee-cup:before{content:"\E6B8"}.el-icon-water-cup:before{content:"\E6B9"}.el-icon-hot-water:before{content:"\E6BA"}.el-icon-ice-cream:before{content:"\E6BB"}.el-icon-dessert:before{content:"\E6BC"}.el-icon-sugar:before{content:"\E6BD"}.el-icon-tableware:before{content:"\E6BE"}.el-icon-burger:before{content:"\E6BF"}.el-icon-knife-fork:before{content:"\E6C1"}.el-icon-fork-spoon:before{content:"\E6C2"}.el-icon-chicken:before{content:"\E6C3"}.el-icon-food:before{content:"\E6C4"}.el-icon-dish-1:before{content:"\E6C5"}.el-icon-dish:before{content:"\E6C6"}.el-icon-moon-night:before{content:"\E6EE"}.el-icon-moon:before{content:"\E6F0"}.el-icon-cloudy-and-sunny:before{content:"\E6F1"}.el-icon-partly-cloudy:before{content:"\E6F2"}.el-icon-cloudy:before{content:"\E6F3"}.el-icon-sunny:before{content:"\E6F6"}.el-icon-sunset:before{content:"\E6F7"}.el-icon-sunrise-1:before{content:"\E6F8"}.el-icon-sunrise:before{content:"\E6F9"}.el-icon-heavy-rain:before{content:"\E6FA"}.el-icon-lightning:before{content:"\E6FB"}.el-icon-light-rain:before{content:"\E6FC"}.el-icon-wind-power:before{content:"\E6FD"}.el-icon-baseball:before{content:"\E712"}.el-icon-soccer:before{content:"\E713"}.el-icon-football:before{content:"\E715"}.el-icon-basketball:before{content:"\E716"}.el-icon-ship:before{content:"\E73F"}.el-icon-truck:before{content:"\E740"}.el-icon-bicycle:before{content:"\E741"}.el-icon-mobile-phone:before{content:"\E6D3"}.el-icon-service:before{content:"\E6D4"}.el-icon-key:before{content:"\E6E2"}.el-icon-unlock:before{content:"\E6E4"}.el-icon-lock:before{content:"\E6E5"}.el-icon-watch:before{content:"\E6FE"}.el-icon-watch-1:before{content:"\E6FF"}.el-icon-timer:before{content:"\E702"}.el-icon-alarm-clock:before{content:"\E703"}.el-icon-map-location:before{content:"\E704"}.el-icon-delete-location:before{content:"\E705"}.el-icon-add-location:before{content:"\E706"}.el-icon-location-information:before{content:"\E707"}.el-icon-location-outline:before{content:"\E708"}.el-icon-location:before{content:"\E79E"}.el-icon-place:before{content:"\E709"}.el-icon-discover:before{content:"\E70A"}.el-icon-first-aid-kit:before{content:"\E70B"}.el-icon-trophy-1:before{content:"\E70C"}.el-icon-trophy:before{content:"\E70D"}.el-icon-medal:before{content:"\E70E"}.el-icon-medal-1:before{content:"\E70F"}.el-icon-stopwatch:before{content:"\E710"}.el-icon-mic:before{content:"\E711"}.el-icon-copy-document:before{content:"\E718"}.el-icon-full-screen:before{content:"\E719"}.el-icon-switch-button:before{content:"\E71B"}.el-icon-aim:before{content:"\E71C"}.el-icon-crop:before{content:"\E71D"}.el-icon-odometer:before{content:"\E71E"}.el-icon-time:before{content:"\E71F"}.el-icon-bangzhu:before{content:"\E724"}.el-icon-close-notification:before{content:"\E726"}.el-icon-microphone:before{content:"\E727"}.el-icon-turn-off-microphone:before{content:"\E728"}.el-icon-position:before{content:"\E729"}.el-icon-postcard:before{content:"\E72A"}.el-icon-message:before{content:"\E72B"}.el-icon-chat-line-square:before{content:"\E72D"}.el-icon-chat-dot-square:before{content:"\E72E"}.el-icon-chat-dot-round:before{content:"\E72F"}.el-icon-chat-square:before{content:"\E730"}.el-icon-chat-line-round:before{content:"\E731"}.el-icon-chat-round:before{content:"\E732"}.el-icon-set-up:before{content:"\E733"}.el-icon-turn-off:before{content:"\E734"}.el-icon-open:before{content:"\E735"}.el-icon-connection:before{content:"\E736"}.el-icon-link:before{content:"\E737"}.el-icon-cpu:before{content:"\E738"}.el-icon-thumb:before{content:"\E739"}.el-icon-female:before{content:"\E73A"}.el-icon-male:before{content:"\E73B"}.el-icon-guide:before{content:"\E73C"}.el-icon-news:before{content:"\E73E"}.el-icon-price-tag:before{content:"\E744"}.el-icon-discount:before{content:"\E745"}.el-icon-wallet:before{content:"\E747"}.el-icon-coin:before{content:"\E748"}.el-icon-money:before{content:"\E749"}.el-icon-bank-card:before{content:"\E74A"}.el-icon-box:before{content:"\E74B"}.el-icon-present:before{content:"\E74C"}.el-icon-sell:before{content:"\E6D5"}.el-icon-sold-out:before{content:"\E6D6"}.el-icon-shopping-bag-2:before{content:"\E74D"}.el-icon-shopping-bag-1:before{content:"\E74E"}.el-icon-shopping-cart-2:before{content:"\E74F"}.el-icon-shopping-cart-1:before{content:"\E750"}.el-icon-shopping-cart-full:before{content:"\E751"}.el-icon-smoking:before{content:"\E752"}.el-icon-no-smoking:before{content:"\E753"}.el-icon-house:before{content:"\E754"}.el-icon-table-lamp:before{content:"\E755"}.el-icon-school:before{content:"\E756"}.el-icon-office-building:before{content:"\E757"}.el-icon-toilet-paper:before{content:"\E758"}.el-icon-notebook-2:before{content:"\E759"}.el-icon-notebook-1:before{content:"\E75A"}.el-icon-files:before{content:"\E75B"}.el-icon-collection:before{content:"\E75C"}.el-icon-receiving:before{content:"\E75D"}.el-icon-suitcase-1:before{content:"\E760"}.el-icon-suitcase:before{content:"\E761"}.el-icon-film:before{content:"\E763"}.el-icon-collection-tag:before{content:"\E765"}.el-icon-data-analysis:before{content:"\E766"}.el-icon-pie-chart:before{content:"\E767"}.el-icon-data-board:before{content:"\E768"}.el-icon-data-line:before{content:"\E76D"}.el-icon-reading:before{content:"\E769"}.el-icon-magic-stick:before{content:"\E76A"}.el-icon-coordinate:before{content:"\E76B"}.el-icon-mouse:before{content:"\E76C"}.el-icon-brush:before{content:"\E76E"}.el-icon-headset:before{content:"\E76F"}.el-icon-umbrella:before{content:"\E770"}.el-icon-scissors:before{content:"\E771"}.el-icon-mobile:before{content:"\E773"}.el-icon-attract:before{content:"\E774"}.el-icon-monitor:before{content:"\E775"}.el-icon-search:before{content:"\E778"}.el-icon-takeaway-box:before{content:"\E77A"}.el-icon-paperclip:before{content:"\E77D"}.el-icon-printer:before{content:"\E77E"}.el-icon-document-add:before{content:"\E782"}.el-icon-document:before{content:"\E785"}.el-icon-document-checked:before{content:"\E786"}.el-icon-document-copy:before{content:"\E787"}.el-icon-document-delete:before{content:"\E788"}.el-icon-document-remove:before{content:"\E789"}.el-icon-tickets:before{content:"\E78B"}.el-icon-folder-checked:before{content:"\E77F"}.el-icon-folder-delete:before{content:"\E780"}.el-icon-folder-remove:before{content:"\E781"}.el-icon-folder-add:before{content:"\E783"}.el-icon-folder-opened:before{content:"\E784"}.el-icon-folder:before{content:"\E78A"}.el-icon-edit-outline:before{content:"\E764"}.el-icon-edit:before{content:"\E78C"}.el-icon-date:before{content:"\E78E"}.el-icon-c-scale-to-original:before{content:"\E7C6"}.el-icon-view:before{content:"\E6CE"}.el-icon-loading:before{content:"\E6CF"}.el-icon-rank:before{content:"\E6D1"}.el-icon-sort-down:before{content:"\E7C4"}.el-icon-sort-up:before{content:"\E7C5"}.el-icon-sort:before{content:"\E6D2"}.el-icon-finished:before{content:"\E6CD"}.el-icon-refresh-left:before{content:"\E6C7"}.el-icon-refresh-right:before{content:"\E6C8"}.el-icon-refresh:before{content:"\E6D0"}.el-icon-video-play:before{content:"\E7C0"}.el-icon-video-pause:before{content:"\E7C1"}.el-icon-d-arrow-right:before{content:"\E6DC"}.el-icon-d-arrow-left:before{content:"\E6DD"}.el-icon-arrow-up:before{content:"\E6E1"}.el-icon-arrow-down:before{content:"\E6DF"}.el-icon-arrow-right:before{content:"\E6E0"}.el-icon-arrow-left:before{content:"\E6DE"}.el-icon-top-right:before{content:"\E6E7"}.el-icon-top-left:before{content:"\E6E8"}.el-icon-top:before{content:"\E6E6"}.el-icon-bottom:before{content:"\E6EB"}.el-icon-right:before{content:"\E6E9"}.el-icon-back:before{content:"\E6EA"}.el-icon-bottom-right:before{content:"\E6EC"}.el-icon-bottom-left:before{content:"\E6ED"}.el-icon-caret-top:before{content:"\E78F"}.el-icon-caret-bottom:before{content:"\E790"}.el-icon-caret-right:before{content:"\E791"}.el-icon-caret-left:before{content:"\E792"}.el-icon-d-caret:before{content:"\E79A"}.el-icon-share:before{content:"\E793"}.el-icon-menu:before{content:"\E798"}.el-icon-s-grid:before{content:"\E7A6"}.el-icon-s-check:before{content:"\E7A7"}.el-icon-s-data:before{content:"\E7A8"}.el-icon-s-opportunity:before{content:"\E7AA"}.el-icon-s-custom:before{content:"\E7AB"}.el-icon-s-claim:before{content:"\E7AD"}.el-icon-s-finance:before{content:"\E7AE"}.el-icon-s-comment:before{content:"\E7AF"}.el-icon-s-flag:before{content:"\E7B0"}.el-icon-s-marketing:before{content:"\E7B1"}.el-icon-s-shop:before{content:"\E7B4"}.el-icon-s-open:before{content:"\E7B5"}.el-icon-s-management:before{content:"\E7B6"}.el-icon-s-ticket:before{content:"\E7B7"}.el-icon-s-release:before{content:"\E7B8"}.el-icon-s-home:before{content:"\E7B9"}.el-icon-s-promotion:before{content:"\E7BA"}.el-icon-s-operation:before{content:"\E7BB"}.el-icon-s-unfold:before{content:"\E7BC"}.el-icon-s-fold:before{content:"\E7A9"}.el-icon-s-platform:before{content:"\E7BD"}.el-icon-s-order:before{content:"\E7BE"}.el-icon-s-cooperation:before{content:"\E7BF"}.el-icon-bell:before{content:"\E725"}.el-icon-message-solid:before{content:"\E799"}.el-icon-video-camera:before{content:"\E772"}.el-icon-video-camera-solid:before{content:"\E796"}.el-icon-camera:before{content:"\E779"}.el-icon-camera-solid:before{content:"\E79B"}.el-icon-download:before{content:"\E77C"}.el-icon-upload2:before{content:"\E77B"}.el-icon-upload:before{content:"\E7C3"}.el-icon-picture-outline-round:before{content:"\E75F"}.el-icon-picture-outline:before{content:"\E75E"}.el-icon-picture:before{content:"\E79F"}.el-icon-close:before{content:"\E6DB"}.el-icon-check:before{content:"\E6DA"}.el-icon-plus:before{content:"\E6D9"}.el-icon-minus:before{content:"\E6D8"}.el-icon-help:before{content:"\E73D"}.el-icon-s-help:before{content:"\E7B3"}.el-icon-circle-close:before{content:"\E78D"}.el-icon-circle-check:before{content:"\E720"}.el-icon-circle-plus-outline:before{content:"\E723"}.el-icon-remove-outline:before{content:"\E722"}.el-icon-zoom-out:before{content:"\E776"}.el-icon-zoom-in:before{content:"\E777"}.el-icon-error:before{content:"\E79D"}.el-icon-success:before{content:"\E79C"}.el-icon-circle-plus:before{content:"\E7A0"}.el-icon-remove:before{content:"\E7A2"}.el-icon-info:before{content:"\E7A1"}.el-icon-question:before{content:"\E7A4"}.el-icon-warning-outline:before{content:"\E6C9"}.el-icon-warning:before{content:"\E7A3"}.el-icon-goods:before{content:"\E7C2"}.el-icon-s-goods:before{content:"\E7B2"}.el-icon-star-off:before{content:"\E717"}.el-icon-star-on:before{content:"\E797"}.el-icon-more-outline:before{content:"\E6CC"}.el-icon-more:before{content:"\E794"}.el-icon-phone-outline:before{content:"\E6CB"}.el-icon-phone:before{content:"\E795"}.el-icon-user:before{content:"\E6E3"}.el-icon-user-solid:before{content:"\E7A5"}.el-icon-setting:before{content:"\E6CA"}.el-icon-s-tools:before{content:"\E7AC"}.el-icon-delete:before{content:"\E6D7"}.el-icon-delete-solid:before{content:"\E7C9"}.el-icon-eleme:before{content:"\E7C7"}.el-icon-platform-eleme:before{content:"\E7CA"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination:after,.el-pagination:before{display:table;content:""}.el-pagination:after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409eff}.el-pagination button:disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:50% no-repeat #fff;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#c0c4cc;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more:before,.el-pagination--small li.more:before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409eff}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#c0c4cc}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409eff}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409eff;color:#fff}.el-dialog,.el-pager li{background:#fff;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-pager .more:before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#c0c4cc}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409eff}.el-pager li.active{color:#409eff;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{to{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409eff}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fff}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#f5f7fa}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#fff}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button:before{content:"";position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:hsla(0,0%,100%,.5)}.el-dropdown .el-dropdown__caret-button:hover:before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #ebeef5}.el-dropdown-menu__item--divided:before{content:"";height:6px;display:block;margin:0 -20px;background-color:#fff}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:1px solid #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0}.el-menu,.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu:after,.el-menu:before{display:table;content:""}.el-menu:after{clear:both}.el-menu.el-menu--horizontal{border-bottom:1px solid #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409eff;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409eff;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409eff}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409eff}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#fff;border:1px solid #dcdfe6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409eff}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #409eff;box-shadow:-1px 0 0 0 #409eff}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#f2f6fc}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409eff}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #dcdfe6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#dcdfe6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#409eff;background-color:#409eff}.el-switch.is-checked .el-switch__core:after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409eff;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected:after{position:absolute;right:20px;font-family:element-icons;content:"\E6DA";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item,.el-select .el-tag,.el-table{-webkit-box-sizing:border-box}.el-select-dropdown__item.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#409eff;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type):after{content:"";position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#e4e7ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#c0c4cc}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409eff}.el-select .el-input .el-select__caret{color:#c0c4cc;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotate(180deg);transform:rotate(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotate(0);transform:rotate(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotate(180deg);transform:rotate(180deg);border-radius:100%;color:#c0c4cc;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#e4e7ed}.el-select .el-input.is-focus .el-input__inner{border-color:#409eff}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#c0c4cc;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#c0c4cc;right:-7px;top:0;color:#fff}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#fff}.el-select .el-tag__close.el-icon-close:before{display:block;-webkit-transform:translateY(.5px);transform:translateY(.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#f5f7fa}.el-table th,.el-table tr{background-color:#fff}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table th div{padding-right:10px;overflow:hidden;text-overflow:ellipsis}.el-table--border td:first-child .cell,.el-table--border th:first-child .cell,.el-table .cell,.el-table th div{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #ebeef5}.el-table th.is-sortable{cursor:pointer}.el-table th{white-space:nowrap;overflow:hidden;-moz-user-select:none;user-select:none}.el-slider__button-wrapper,.el-table th,.el-time-panel{-webkit-user-select:none;-ms-user-select:none}.el-table th div{line-height:40px;white-space:nowrap}.el-table th>.cell,.el-table th div{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box}.el-table th>.cell{position:relative;word-wrap:normal;text-overflow:ellipsis;vertical-align:middle;width:100%}.el-table th>.cell.highlight{color:#409eff}.el-table th.required>div:before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;white-space:normal;word-break:break-all;line-height:23px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #ebeef5}.el-table--border:after,.el-table--group:after,.el-table:before{content:"";position:absolute;background-color:#ebeef5;z-index:1}.el-table--border:after,.el-table--group:after{top:0;right:0;width:1px;height:100%}.el-table:before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #ebeef5}.el-table--border th,.el-table--border th.gutter:last-of-type,.el-table__fixed-right-patch{border-bottom:1px solid #ebeef5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right:before,.el-table__fixed:before{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#ebeef5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#fff}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #ebeef5;background-color:#f5f7fa;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #ebeef5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#f5f7fa;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #ebeef5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#c0c4cc;top:5px}.el-table .sort-caret.descending{border-top-color:#c0c4cc;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409eff}.el-table .descending .sort-caret.descending{border-top-color:#409eff}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#fafafa}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#f5f7fa}.el-table__body tr.current-row>td{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #ebeef5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#f5f7fa}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #ebeef5;border-radius:2px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409eff;color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #ebeef5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div,.el-date-table td.in-range div,.el-date-table td.in-range div:hover{background-color:#f2f6fc}.el-table-filter__bottom button:hover{color:#409eff}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;text-align:center;cursor:pointer;position:relative}.el-date-table td,.el-date-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td div{padding:3px 0}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#c0c4cc}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409eff;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#fff}.el-date-table td.available:hover{color:#409eff}.el-date-table td.current:not(.disabled) span{color:#fff;background-color:#409eff}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#fff}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409eff}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#f5f7fa;opacity:1;cursor:not-allowed;color:#c0c4cc}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#f2f6fc;border-radius:15px}.el-date-table td.selected div:hover{background-color:#f2f6fc}.el-date-table td.selected span{background-color:#409eff;color:#fff;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:1px solid #ebeef5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409eff;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#fff}.el-month-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-month-table td.disabled .cell:hover{color:#c0c4cc}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409eff}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#f2f6fc}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#fff}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#fff;background-color:#409eff}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409eff}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409eff;font-weight:700}.el-year-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-year-table td.disabled .cell:hover{color:#c0c4cc}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409eff}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#fff}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:1px solid #ebeef5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409eff}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409eff;font-weight:700}.time-select-item.disabled{color:#e4e7ed;cursor:not-allowed}.time-select-item:hover{background-color:#f5f7fa;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#c0c4cc;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input:-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::placeholder{color:#c0c4cc}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#c0c4cc;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409eff}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#e4e7ed}.el-range-editor.is-disabled input{background-color:#f5f7fa;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::placeholder{color:#c0c4cc}.el-range-editor.is-disabled .el-range-separator{color:#c0c4cc}.el-picker-panel{color:#606266;border:1px solid #e4e7ed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#fff;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel,.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper:after,.el-picker-panel__body:after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#fff;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409eff}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409eff}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409eff}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#fff;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#fff;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409eff}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list:after,.el-time-spinner__list:before{content:"";display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#f5f7fa;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#c0c4cc;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #e4e7ed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content:after,.el-time-panel__content:before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #e4e7ed;border-bottom:1px solid #e4e7ed}.el-time-panel__content:after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content:before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds:after{left:66.66667%}.el-time-panel__content.has-seconds:before{padding-left:33.33333%}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409eff}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #e4e7ed}.el-popover{position:absolute;background:#fff;min-width:150px;border:1px solid #ebeef5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#fff;border-radius:4px;border:1px solid #ebeef5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper:after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#f56c6c}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409eff}.el-message-box__content{position:relative;padding:10px 15px;color:#606266;font-size:14px}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status:before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67c23a}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#e6a23c}.el-message-box__status.el-icon-error{color:#f56c6c}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#f56c6c;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-container,.el-container.is-vertical,.el-link,.el-steps--vertical{-webkit-box-direction:normal}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb:after,.el-breadcrumb:before{display:table;content:""}.el-breadcrumb:after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#c0c4cc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner.is-link,.el-breadcrumb__inner a{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner.is-link:hover,.el-breadcrumb__inner a:hover{color:#409eff;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item:after,.el-form-item:before{display:table;content:""}.el-form-item:after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content:after,.el-form-item__content:before{display:table;content:""}.el-form-item__content:after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#f56c6c;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:"*";color:#f56c6c;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#f56c6c}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409eff;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-collapse-item__arrow,.el-tabs__nav{-webkit-transition:-webkit-transform .3s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8);transform:scale(.8)}.el-tabs__new-tab:hover{color:#409eff}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap:after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#e4e7ed;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap:after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;transition:-webkit-transform .3s;-webkit-transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409eff inset;box-shadow:inset 0 0 2px 2px #409eff;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#c0c4cc;color:#fff}.el-tabs__item.is-active{color:#409eff}.el-tabs__item:hover{color:#409eff;cursor:pointer}.el-tabs__item.is-disabled{color:#c0c4cc;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #e4e7ed}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #e4e7ed;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #e4e7ed;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#fff}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#fff;border:1px solid #dcdfe6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#f5f7fa;border-bottom:1px solid #e4e7ed;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409eff;background-color:#fff;border-right-color:#dcdfe6;border-left-color:#dcdfe6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409eff}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#c0c4cc}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #dcdfe6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left:after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left:after,.el-tabs--left .el-tabs__nav-wrap.is-right:after,.el-tabs--right .el-tabs__nav-wrap.is-left:after,.el-tabs--right .el-tabs__nav-wrap.is-right:after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border:1px solid #e4e7ed;border-bottom:none;border-left:none;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #e4e7ed;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:none;border-top:1px solid #e4e7ed;border-right:1px solid #fff}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #e4e7ed;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right:after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #e4e7ed;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:none;border-top:1px solid #e4e7ed;border-left:1px solid #fff}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #e4e7ed;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#fff;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409eff}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#f5f7fa}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409eff;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#c0c4cc;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#c0c4cc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#c0c4cc}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#fff}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67c23a}.el-alert--success.is-light .el-alert__description{color:#67c23a}.el-alert--success.is-dark{background-color:#67c23a;color:#fff}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#fff}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#e6a23c}.el-alert--warning.is-light .el-alert__description{color:#e6a23c}.el-alert--warning.is-dark{background-color:#e6a23c;color:#fff}.el-alert--error.is-light{background-color:#fef0f0;color:#f56c6c}.el-alert--error.is-light .el-alert__description{color:#f56c6c}.el-alert--error.is-dark{background-color:#f56c6c;color:#fff}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#f56c6c}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#e6a23c}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409eff}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409eff}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #dcdfe6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #dcdfe6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#e4e7ed;color:#e4e7ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#e4e7ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #dcdfe6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #dcdfe6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow:after{content:" ";border-width:5px}.el-progress-bar__inner:after,.el-row:after,.el-row:before,.el-slider:after,.el-slider:before,.el-slider__button-wrapper:after,.el-upload-cover:after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow:after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow:after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow:after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow:after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow:after{border-right-color:#fff}.el-slider:after,.el-slider:before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper:after{vertical-align:middle;display:inline-block}.el-slider:after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#e4e7ed;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button{border-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409eff;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:transparent;text-align:center;-moz-user-select:none;user-select:none;line-height:normal}.el-slider__button,.el-slider__button-wrapper,.el-step__icon-inner{-webkit-user-select:none;-ms-user-select:none}.el-slider__button-wrapper:after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409eff;background-color:#fff;border-radius:50%;-webkit-transition:.2s;transition:.2s;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px}.el-slider.is-vertical .el-slider__button-wrapper,.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #dcdfe6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#c0c4cc}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409eff}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:hsla(0,0%,100%,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-2,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-push-0,.el-col-push-1,.el-col-push-2,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409eff;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409eff;stroke-linecap:round}.el-loading-spinner i{color:#409eff}@-webkit-keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row:after,.el-row:before{display:table}.el-row:after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409eff;color:#409eff}.el-upload:focus .el-upload-dragger{border-color:#409eff}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#c0c4cc;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #dcdfe6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409eff;font-style:normal}.el-upload-dragger:hover{border-color:#409eff}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409eff}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67c23a}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409eff}.el-upload-list__item:hover{background-color:#f5f7fa}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409eff;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409eff}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#fff}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover:after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#fff;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#fff;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner:after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-warning .el-progress-bar__inner{background-color:#e6a23c}.el-progress.is-warning .el-progress__text{color:#e6a23c}.el-progress.is-exception .el-progress-bar__inner{background-color:#f56c6c}.el-progress.is-exception .el-progress__text{color:#f56c6c}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#ebeef5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409eff;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner:after{height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#e6a23c}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#f56c6c}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#c0c4cc;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#f56c6c}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#e6a23c}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#f56c6c;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409eff}.el-badge__content--success{background-color:#67c23a}.el-badge__content--warning{background-color:#e6a23c}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#f56c6c}.el-card{border:1px solid #ebeef5;background-color:#fff;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#c0c4cc;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:-webkit-box;display:-ms-flexbox;display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#c0c4cc;border-color:#c0c4cc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#f56c6c;border-color:#f56c6c}.el-step__head.is-finish{color:#409eff;border-color:#409eff}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;-moz-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-button,.el-checkbox,.el-step__icon-inner{-webkit-user-select:none;-ms-user-select:none}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#c0c4cc}.el-step__line-inner{display:block;border:1px solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#c0c4cc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#f56c6c}.el-step__title.is-finish{color:#409eff}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#c0c4cc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#f56c6c}.el-step__description.is-finish{color:#409eff}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:-webkit-box;display:-ms-flexbox;display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow:after,.el-step.is-simple .el-step__arrow:before{content:"";display:inline-block;position:absolute;height:15px;width:1px;background:#c0c4cc}.el-step.is-simple .el-step__arrow:before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow:after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#c0c4cc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item--card,.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#fff;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active,.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active,.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45);transform:scale(.45)}.collapse-transition{-webkit-transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out;transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out}.horizontal-collapse-transition{-webkit-transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out;transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #ebeef5;border-bottom:1px solid #ebeef5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#fff;color:#303133;cursor:pointer;border-bottom:1px solid #ebeef5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;transition:-webkit-transform .3s;-webkit-transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409eff}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#fff;overflow:hidden;box-sizing:border-box;border-bottom:1px solid #ebeef5}.el-cascader__tags,.el-collapse-item__wrap,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0,0,0,.03));filter:drop-shadow(0 2px 12px rgba(0,0,0,.03))}.el-popper .popper__arrow:after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#ebeef5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#ebeef5}.el-popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#ebeef5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow:after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#ebeef5}.el-popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-tag{background-color:#ecf5ff;display:inline-block;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#409eff;border:1px solid #d9ecff;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409eff}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#fff;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#fff;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67c23a}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#fff;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close:before{display:block}.el-tag--dark{background-color:#409eff;color:#fff}.el-tag--dark,.el-tag--dark.is-hit{border-color:#409eff}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#fff;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#fff;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67c23a}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#fff;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409eff}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#fff;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#fff;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#fff;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#c0c4cc}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409eff}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#fff;border:1px solid #e4e7ed;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#c0c4cc;color:#fff}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#f5f7fa}.el-cascader__suggestion-item.is-checked{color:#409eff;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#c0c4cc}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#c0c4cc}.el-cascader__search-input:-ms-input-placeholder{color:#c0c4cc}.el-cascader__search-input::-ms-input-placeholder{color:#c0c4cc}.el-cascader__search-input::placeholder{color:#c0c4cc}.el-color-predefine{font-size:12px;margin-top:8px;width:280px}.el-color-predefine,.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex}.el-color-predefine__colors{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409eff;box-shadow:0 0 3px 2px #409eff}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(hsla(0,0%,100%,0)));background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(transparent));background:linear-gradient(0deg,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,#fff);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,#fff)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper:after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409eff;border-color:#409eff}.el-color-dropdown__link-btn{cursor:pointer;color:#409eff;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409eff,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:hsla(0,0%,100%,.7)}.el-color-picker__trigger{display:inline-block;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;cursor:pointer}.el-color-picker__color,.el-color-picker__trigger{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-color-picker__color{display:block;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999}.el-color-picker__empty,.el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#fff;background-image:none;border:1px solid #dcdfe6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea__inner:hover{border-color:#c0c4cc}.el-textarea__inner:focus{outline:0;border-color:#409eff}.el-textarea .el-input__count{color:#909399;background:#fff;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea.is-exceed .el-textarea__inner{border-color:#f56c6c}.el-textarea.is-exceed .el-input__count{color:#f56c6c}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-button-group>.el-button.is-active,.el-button-group>.el-button.is-disabled,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#fff;line-height:normal;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-button,.el-input__inner,.el-transfer-panel{-webkit-box-sizing:border-box}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#c0c4cc;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409eff;outline:0}.el-input__suffix{right:5px;-webkit-transition:all .3s;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px}.el-input__icon,.el-input__prefix{-webkit-transition:all .3s;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;line-height:40px}.el-input__icon:after{content:"";height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input.is-exceed .el-input__inner{border-color:#f56c6c}.el-input.is-exceed .el-input__suffix .el-input__count{color:#f56c6c}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;border:1px solid #dcdfe6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;-moz-user-select:none;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409eff;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#fff;border-color:#409eff;color:#409eff}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#fff;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#fff;border-color:#ebeef5;color:#c0c4cc}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:"";position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:hsla(0,0%,100%,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#fff;background-color:#409eff;border-color:#409eff}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#fff}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#fff;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409eff;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409eff;border-color:#409eff;color:#fff}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#fff;background-color:#67c23a;border-color:#67c23a}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#fff}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#fff}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#fff;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67c23a;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67c23a;border-color:#67c23a;color:#fff}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#fff;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#fff;background-color:#e6a23c;border-color:#e6a23c}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#fff}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#fff}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#fff;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#e6a23c;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#e6a23c;border-color:#e6a23c;color:#fff}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#fff;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#fff;background-color:#f56c6c;border-color:#f56c6c}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#fff}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#fff}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#fff;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#f56c6c;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#f56c6c;border-color:#f56c6c;color:#fff}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#fff;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#fff;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#fff}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#fff}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#fff;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#fff}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#fff;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409eff;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group:after,.el-button-group:before{display:table;content:""}.el-button-group:after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#fff;background-color:#409eff;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #dcdfe6;background-color:#f5f7fa;color:#c0c4cc}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #ebeef5;border-radius:4px;overflow:hidden;background:#fff;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409eff}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#f5f7fa;margin:0;padding-left:15px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-divider__text,.el-link{font-weight:500;font-size:14px}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#fff;margin:0;padding:0;border-top:1px solid #ebeef5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner:after{height:6px;width:3px;left:4px}.el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;min-width:0}.el-aside,.el-container,.el-header{-webkit-box-sizing:border-box}.el-container.is-vertical{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px}.el-aside,.el-header{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;padding:20px}.el-footer,.el-main{-webkit-box-sizing:border-box;box-sizing:border-box}.el-footer{padding:0 20px;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #e4e7ed}.el-timeline-item__icon{color:#fff;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#e4e7ed;border-radius:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409eff}.el-timeline-item__node--success{background-color:#67c23a}.el-timeline-item__node--warning{background-color:#e6a23c}.el-timeline-item__node--danger{background-color:#f56c6c}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0}.el-link.is-underline:hover:after{content:"";position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409eff}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409eff}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409eff}.el-link.el-link--default.is-disabled{color:#c0c4cc}.el-link.el-link--primary{color:#409eff}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#f56c6c}.el-link.el-link--danger{color:#f56c6c}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67c23a}.el-link.el-link--success{color:#67c23a}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#e6a23c}.el-link.el-link--warning{color:#e6a23c}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#dcdfe6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#fff;padding:0 20px;color:#303133}.el-image__error,.el-image__placeholder{background:#f5f7fa}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-calendar__header,.el-image__error{display:-webkit-box;display:-ms-flexbox}.el-image__error{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#c0c4cc;vertical-align:middle}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #ebeef5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#c0c4cc}.el-backtop,.el-calendar-table td.is-today{color:#409eff}.el-calendar-table td{border-bottom:1px solid #ebeef5;border-right:1px solid #ebeef5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#f2f8fe}.el-calendar-table tr:first-child td{border-top:1px solid #ebeef5}.el-calendar-table tr td:first-child{border-left:1px solid #ebeef5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#f2f8fe}.el-backtop{position:fixed;background-color:#fff;width:40px;height:40px;border-radius:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#f2f6fc}.el-page-header{line-height:24px}.el-page-header,.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex}.el-page-header__left{cursor:pointer;margin-right:40px;position:relative}.el-page-header__left:after{content:"";position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#dcdfe6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox,.el-checkbox-button__inner,.el-radio{font-weight:500;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409eff}.el-checkbox.is-bordered.is-disabled{border-color:#ebeef5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#dcdfe6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner:after{cursor:not-allowed;border-color:#c0c4cc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after{border-color:#c0c4cc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before{background-color:#c0c4cc;border-color:#c0c4cc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409eff;border-color:#409eff}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#c0c4cc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner:after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409eff}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409eff}.el-checkbox__input.is-indeterminate .el-checkbox__inner:before{content:"";position:absolute;display:block;background-color:#fff;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner:after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #dcdfe6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409eff}.el-checkbox__inner:after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-child{margin-right:0}.el-checkbox-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#fff;border:1px solid #dcdfe6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409eff}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-radio,.el-radio__input{line-height:1;outline:0;white-space:nowrap}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409eff}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#ebeef5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409eff}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio{color:#606266;cursor:pointer;margin-right:30px}.el-cascader-node>.el-checkbox,.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409eff}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#ebeef5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#e4e7ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner:after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner:after{background-color:#c0c4cc}.el-radio__input.is-disabled+span.el-radio__label{color:#c0c4cc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409eff;background:#409eff}.el-radio__input.is-checked .el-radio__inner:after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409eff}.el-radio__input.is-focus .el-radio__inner{border-color:#409eff}.el-radio__inner{border:1px solid #dcdfe6;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#409eff}.el-radio__inner:after{width:4px;height:4px;border-radius:100%;background-color:#fff;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-radio__label{font-size:14px;padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity .34s ease-out;transition:opacity .34s ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:background-color .3s;transition:background-color .3s}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity .12s ease-out;transition:opacity .12s ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #e4e7ed;border-radius:4px}.el-cascader-menu{min-width:180px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;border-right:1px solid #e4e7ed}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#c0c4cc}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409eff;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#f5f7fa}.el-cascader-node.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#c0c4cc;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{width:100%;height:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px} \ No newline at end of file diff --git a/priv/static/adminfe/chunk-elementUI.f74c256b.css b/priv/static/adminfe/chunk-elementUI.f74c256b.css deleted file mode 100644 index c8d56344e..000000000 --- a/priv/static/adminfe/chunk-elementUI.f74c256b.css +++ /dev/null @@ -1 +0,0 @@ -.el-pagination--small .arrow.disabled,.el-table--hidden,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(static/fonts/element-icons.2fad952.woff) format("woff"),url(static/fonts/element-icons.6f0a763.ttf) format("truetype");font-weight:400;font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-info:before{content:"\E61A"}.el-icon-error:before{content:"\E62C"}.el-icon-success:before{content:"\E62D"}.el-icon-warning:before{content:"\E62E"}.el-icon-question:before{content:"\E634"}.el-icon-back:before{content:"\E606"}.el-icon-arrow-left:before{content:"\E600"}.el-icon-arrow-down:before{content:"\E603"}.el-icon-arrow-right:before{content:"\E604"}.el-icon-arrow-up:before{content:"\E605"}.el-icon-caret-left:before{content:"\E60A"}.el-icon-caret-bottom:before{content:"\E60B"}.el-icon-caret-top:before{content:"\E60C"}.el-icon-caret-right:before{content:"\E60E"}.el-icon-d-arrow-left:before{content:"\E610"}.el-icon-d-arrow-right:before{content:"\E613"}.el-icon-minus:before{content:"\E621"}.el-icon-plus:before{content:"\E62B"}.el-icon-remove:before{content:"\E635"}.el-icon-circle-plus:before{content:"\E601"}.el-icon-remove-outline:before{content:"\E63C"}.el-icon-circle-plus-outline:before{content:"\E602"}.el-icon-close:before{content:"\E60F"}.el-icon-check:before{content:"\E611"}.el-icon-circle-close:before{content:"\E607"}.el-icon-circle-check:before{content:"\E639"}.el-icon-circle-close-outline:before{content:"\E609"}.el-icon-circle-check-outline:before{content:"\E63E"}.el-icon-zoom-out:before{content:"\E645"}.el-icon-zoom-in:before{content:"\E641"}.el-icon-d-caret:before{content:"\E615"}.el-icon-sort:before{content:"\E640"}.el-icon-sort-down:before{content:"\E630"}.el-icon-sort-up:before{content:"\E631"}.el-icon-tickets:before{content:"\E63F"}.el-icon-document:before{content:"\E614"}.el-icon-goods:before{content:"\E618"}.el-icon-sold-out:before{content:"\E63B"}.el-icon-news:before{content:"\E625"}.el-icon-message:before{content:"\E61B"}.el-icon-date:before{content:"\E608"}.el-icon-printer:before{content:"\E62F"}.el-icon-time:before{content:"\E642"}.el-icon-bell:before{content:"\E622"}.el-icon-mobile-phone:before{content:"\E624"}.el-icon-service:before{content:"\E63A"}.el-icon-view:before{content:"\E643"}.el-icon-menu:before{content:"\E620"}.el-icon-more:before{content:"\E646"}.el-icon-more-outline:before{content:"\E626"}.el-icon-star-on:before{content:"\E637"}.el-icon-star-off:before{content:"\E63D"}.el-icon-location:before{content:"\E61D"}.el-icon-location-outline:before{content:"\E61F"}.el-icon-phone:before{content:"\E627"}.el-icon-phone-outline:before{content:"\E628"}.el-icon-picture:before{content:"\E629"}.el-icon-picture-outline:before{content:"\E62A"}.el-icon-delete:before{content:"\E612"}.el-icon-search:before{content:"\E619"}.el-icon-edit:before{content:"\E61C"}.el-icon-edit-outline:before{content:"\E616"}.el-icon-rank:before{content:"\E632"}.el-icon-refresh:before{content:"\E633"}.el-icon-share:before{content:"\E636"}.el-icon-setting:before{content:"\E638"}.el-icon-upload:before{content:"\E60D"}.el-icon-upload2:before{content:"\E644"}.el-icon-download:before{content:"\E617"}.el-icon-loading:before{content:"\E61E"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotating{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination:after,.el-pagination:before{display:table;content:""}.el-pagination:after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409eff}.el-pagination button:disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:50% no-repeat #fff;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#c0c4cc;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more:before,.el-pagination--small li.more:before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409eff}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#c0c4cc}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409eff}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409eff;color:#fff}.el-dialog,.el-pager li{background:#fff;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{user-select:none;list-style:none;font-size:0}.el-pager,.el-radio,.el-table th{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-pager .more:before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#c0c4cc}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409eff}.el-pager li.active{color:#409eff;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{to{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409eff}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fff}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#f5f7fa}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#fff}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button:before{content:"";position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:hsla(0,0%,100%,.5)}.el-dropdown .el-dropdown__caret-button:hover:before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);max-height:400px;overflow:auto}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #ebeef5}.el-dropdown-menu__item--divided:before{content:"";height:6px;display:block;margin:0 -20px;background-color:#fff}.el-menu:after,.el-menu:before,.el-radio__inner:after,.el-switch__core:after{content:""}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:1px solid #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0}.el-menu,.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu:after,.el-menu:before{display:table}.el-menu:after{clear:both}.el-menu.el-menu--horizontal{border-bottom:1px solid #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409eff;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409eff;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409eff}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409eff}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0;margin-right:30px}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409eff}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#ebeef5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#e4e7ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio:last-child{margin-right:0}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner:after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner:after{background-color:#c0c4cc}.el-radio__input.is-disabled+span.el-radio__label{color:#c0c4cc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409eff;background:#409eff}.el-radio__input.is-checked .el-radio__inner:after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409eff}.el-radio__input.is-focus .el-radio__inner{border-color:#409eff}.el-radio__inner{border:1px solid #dcdfe6;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#409eff}.el-radio__inner:after{width:4px;height:4px;border-radius:100%;background-color:#fff;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio-button,.el-radio-button__inner{display:inline-block;position:relative;outline:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-radio__label{font-size:14px;padding-left:10px}.el-radio-group{display:inline-block;line-height:1;vertical-align:middle;font-size:0}.el-radio-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;background:#fff;border:1px solid #dcdfe6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409eff}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #409eff;box-shadow:-1px 0 0 0 #409eff}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#f2f6fc}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409eff;box-shadow:0 0 2px 2px #409eff}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409eff}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #dcdfe6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#dcdfe6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#409eff;background-color:#409eff}.el-switch.is-checked .el-switch__core:after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409eff;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected:after{position:absolute;right:20px;font-family:element-icons;content:"\E611";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item,.el-select .el-tag,.el-table{-webkit-box-sizing:border-box}.el-select-dropdown__item.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#409eff;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type):after{content:"";position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#e4e7ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#c0c4cc}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409eff}.el-select .el-input .el-select__caret{color:#c0c4cc;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotate(180deg);transform:rotate(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotate(0);transform:rotate(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotate(180deg);transform:rotate(180deg);border-radius:100%;color:#c0c4cc;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#e4e7ed}.el-select .el-input.is-focus .el-input__inner{border-color:#409eff}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#c0c4cc;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#c0c4cc;right:-7px;top:0;color:#fff}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#fff}.el-select .el-tag__close.el-icon-close:before{display:block;-webkit-transform:translateY(.5px);transform:translateY(.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#f5f7fa}.el-table th,.el-table tr{background-color:#fff}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table th div{padding-right:10px;overflow:hidden;text-overflow:ellipsis}.el-table--border td:first-child .cell,.el-table--border th:first-child .cell,.el-table .cell,.el-table th div{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #ebeef5}.el-table th.is-sortable{cursor:pointer}.el-table th{white-space:nowrap;overflow:hidden;-webkit-user-select:none;user-select:none}.el-slider__button-wrapper,.el-table th,.el-time-panel{-moz-user-select:none;-ms-user-select:none}.el-table th div{line-height:40px;white-space:nowrap}.el-table th>.cell,.el-table th div{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box}.el-table th>.cell{position:relative;word-wrap:normal;text-overflow:ellipsis;vertical-align:middle;width:100%}.el-table th>.cell.highlight{color:#409eff}.el-table th.required>div:before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;white-space:normal;word-break:break-all;line-height:23px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #ebeef5}.el-table--border:after,.el-table--group:after,.el-table:before{content:"";position:absolute;background-color:#ebeef5;z-index:1}.el-table--border:after,.el-table--group:after{top:0;right:0;width:1px;height:100%}.el-table:before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #ebeef5}.el-table--border th,.el-table--border th.gutter:last-of-type,.el-table__fixed-right-patch{border-bottom:1px solid #ebeef5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right:before,.el-table__fixed:before{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#ebeef5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#fff}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #ebeef5;background-color:#f5f7fa;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #ebeef5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#f5f7fa;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #ebeef5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#c0c4cc;top:5px}.el-table .sort-caret.descending{border-top-color:#c0c4cc;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409eff}.el-table .descending .sort-caret.descending{border-top-color:#409eff}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#fafafa}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td,.el-table__body tr.current-row>td,.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #ebeef5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#f5f7fa}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:14px;vertical-align:middle;margin-right:5px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #ebeef5;border-radius:2px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409eff;color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #ebeef5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div,.el-date-table td.in-range div,.el-date-table td.in-range div:hover{background-color:#f2f6fc}.el-table-filter__bottom button:hover{color:#409eff}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;text-align:center;cursor:pointer;position:relative}.el-date-table td,.el-date-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td div{padding:3px 0}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#c0c4cc}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409eff;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#fff}.el-date-table td.available:hover{color:#409eff}.el-date-table td.current:not(.disabled) span{color:#fff;background-color:#409eff}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#fff}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409eff}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#f5f7fa;opacity:1;cursor:not-allowed;color:#c0c4cc}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#f2f6fc;border-radius:15px}.el-date-table td.selected div:hover{background-color:#f2f6fc}.el-date-table td.selected span{background-color:#409eff;color:#fff;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:1px solid #ebeef5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409eff;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#fff}.el-month-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-month-table td.disabled .cell:hover{color:#c0c4cc}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409eff}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#f2f6fc}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#fff}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#fff;background-color:#409eff}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409eff}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409eff;font-weight:700}.el-year-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-year-table td.disabled .cell:hover{color:#c0c4cc}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409eff}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#fff}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:1px solid #ebeef5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409eff}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409eff;font-weight:700}.time-select-item.disabled{color:#e4e7ed;cursor:not-allowed}.time-select-item:hover{background-color:#f5f7fa;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#c0c4cc;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input:-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::placeholder{color:#c0c4cc}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#c0c4cc;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409eff}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#e4e7ed}.el-range-editor.is-disabled input{background-color:#f5f7fa;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::placeholder{color:#c0c4cc}.el-range-editor.is-disabled .el-range-separator{color:#c0c4cc}.el-picker-panel{color:#606266;border:1px solid #e4e7ed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#fff;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel,.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper:after,.el-picker-panel__body:after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#fff;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409eff}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409eff}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409eff}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#fff;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#fff;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409eff}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list:after,.el-time-spinner__list:before{content:"";display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#f5f7fa;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#c0c4cc;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #e4e7ed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content:after,.el-time-panel__content:before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #e4e7ed;border-bottom:1px solid #e4e7ed}.el-time-panel__content:after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content:before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds:after{left:66.66667%}.el-time-panel__content.has-seconds:before{padding-left:33.33333%}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409eff}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #e4e7ed}.el-popover{position:absolute;background:#fff;min-width:150px;border:1px solid #ebeef5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#fff;border-radius:4px;border:1px solid #ebeef5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper:after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#f56c6c}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409eff}.el-message-box__content{position:relative;padding:10px 15px;color:#606266;font-size:14px}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status:before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67c23a}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#e6a23c}.el-message-box__status.el-icon-error{color:#f56c6c}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#f56c6c;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}to{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}to{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb:after,.el-breadcrumb:before{display:table;content:""}.el-breadcrumb:after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#c0c4cc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner.is-link,.el-breadcrumb__inner a{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner.is-link:hover,.el-breadcrumb__inner a:hover{color:#409eff;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form-item__content .el-input-group,.el-form-item__label,.el-tag .el-icon-close{vertical-align:middle}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item:after,.el-form-item:before{display:table;content:""}.el-form-item:after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label{text-align:right;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content:after,.el-form-item__content:before{display:table;content:""}.el-form-item__content:after{clear:both}.el-form-item__error{color:#f56c6c;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:"*";color:#f56c6c;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#f56c6c}.el-form-item.is-success .el-input__inner,.el-form-item.is-success .el-input__inner:focus,.el-form-item.is-success .el-textarea__inner,.el-form-item.is-success .el-textarea__inner:focus{border-color:#67c23a}.el-form-item.is-success .el-input-group__append .el-input__inner,.el-form-item.is-success .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-success .el-input__validateIcon{color:#67c23a}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409eff;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8);transform:scale(.8)}.el-tabs__new-tab:hover{color:#409eff}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap:after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#e4e7ed;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap:after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409eff inset;box-shadow:inset 0 0 2px 2px #409eff;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#c0c4cc;color:#fff}.el-tabs__item.is-active{color:#409eff}.el-tabs__item:hover{color:#409eff;cursor:pointer}.el-tabs__item.is-disabled{color:#c0c4cc;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #e4e7ed}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #e4e7ed;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-alert,.el-tag{-webkit-box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #e4e7ed;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#fff}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#fff;border:1px solid #dcdfe6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#f5f7fa;border-bottom:1px solid #e4e7ed;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409eff;background-color:#fff;border-right-color:#dcdfe6;border-left-color:#dcdfe6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409eff}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#c0c4cc}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--left .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--top.el-tabs--card .el-tabs__item:last-child,.el-tabs--top .el-tabs--left .el-tabs__item:last-child,.el-tabs--top .el-tabs--right .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #dcdfe6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left:after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left:after,.el-tabs--left .el-tabs__nav-wrap.is-right:after,.el-tabs--right .el-tabs__nav-wrap.is-left:after,.el-tabs--right .el-tabs__nav-wrap.is-right:after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border:1px solid #e4e7ed;border-bottom:none;border-left:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #e4e7ed;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:none;border-top:1px solid #e4e7ed;border-right:1px solid #fff}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #e4e7ed;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right:after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tag,.slideInLeft-transition,.slideInRight-transition{display:inline-block}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #e4e7ed;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:none;border-top:1px solid #e4e7ed;border-left:1px solid #fff}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #e4e7ed;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}to{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tag{background-color:rgba(64,158,255,.1);padding:0 10px;height:32px;line-height:30px;font-size:12px;color:#409eff;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid rgba(64,158,255,.2);white-space:nowrap}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;top:-1px;right:-5px;color:#409eff}.el-tag .el-icon-close:before{display:block}.el-tag .el-icon-close:hover{background-color:#409eff;color:#fff}.el-tag--info,.el-tag--info .el-tag__close{color:#909399}.el-tag--info{background-color:rgba(144,147,153,.1);border-color:rgba(144,147,153,.2)}.el-tag--info.is-hit{border-color:#909399}.el-tag--info .el-tag__close:hover{background-color:#909399;color:#fff}.el-tag--success{background-color:rgba(103,194,58,.1);border-color:rgba(103,194,58,.2);color:#67c23a}.el-tag--success.is-hit{border-color:#67c23a}.el-tag--success .el-tag__close{color:#67c23a}.el-tag--success .el-tag__close:hover{background-color:#67c23a;color:#fff}.el-tag--warning{background-color:rgba(230,162,60,.1);border-color:rgba(230,162,60,.2);color:#e6a23c}.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--warning .el-tag__close:hover{background-color:#e6a23c;color:#fff}.el-tag--danger{background-color:rgba(245,108,108,.1);border-color:rgba(245,108,108,.2);color:#f56c6c}.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--danger .el-tag__close:hover{background-color:#f56c6c;color:#fff}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-tree{position:relative;cursor:default;background:#fff;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409eff}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#f5f7fa}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409eff;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#c0c4cc;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#c0c4cc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success{background-color:#f0f9eb;color:#67c23a}.el-alert--success .el-alert__description{color:#67c23a}.el-alert--info{background-color:#f4f4f5;color:#909399}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning{background-color:#fdf6ec;color:#e6a23c}.el-alert--warning .el-alert__description{color:#e6a23c}.el-alert--error{background-color:#fef0f0;color:#f56c6c}.el-alert--error .el-alert__description{color:#f56c6c}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;color:#c0c4cc;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#f56c6c}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#e6a23c}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409eff}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409eff}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #dcdfe6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #dcdfe6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#e4e7ed;color:#e4e7ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#e4e7ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #dcdfe6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #dcdfe6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow:after{content:" ";border-width:5px}.el-progress-bar__inner:after,.el-row:after,.el-row:before,.el-slider:after,.el-slider:before,.el-slider__button-wrapper:after,.el-upload-cover:after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow:after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow:after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow:after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow:after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow:after{border-right-color:#fff}.el-slider:after,.el-slider:before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper:after{vertical-align:middle;display:inline-block}.el-slider:after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#e4e7ed;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button{border-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409eff;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;position:absolute;z-index:1001;top:-15px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;user-select:none;line-height:normal}.el-slider__button,.el-slider__button-wrapper,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper:after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409eff;background-color:#fff;border-radius:50%;-webkit-transition:.2s;transition:.2s;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-button,.el-checkbox,.el-slider__button,.el-step__icon-inner{-webkit-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{position:absolute;height:6px;width:6px;border-radius:100%;background-color:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px}.el-slider.is-vertical .el-slider__button-wrapper,.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #dcdfe6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#c0c4cc}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409eff}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:hsla(0,0%,100%,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-2,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-push-0,.el-col-push-1,.el-col-push-2,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409eff;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409eff;stroke-linecap:round}.el-loading-spinner i{color:#409eff}@-webkit-keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes loading-rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row:after,.el-row:before{display:table}.el-row:after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409eff;color:#409eff}.el-upload:focus .el-upload-dragger{border-color:#409eff}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#c0c4cc;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #dcdfe6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409eff;font-style:normal}.el-upload-dragger:hover{border-color:#409eff}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409eff}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67c23a}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409eff}.el-upload-list__item:hover{background-color:#f5f7fa}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409eff;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409eff}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover:after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#fff;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#fff;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle{display:inline-block}.el-progress--circle .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-progress--circle .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner:after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-exception .el-progress-bar__inner{background-color:#f56c6c}.el-progress.is-exception .el-progress__text{color:#f56c6c}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#ebeef5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409eff;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner:after{height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,transform .4s;transition:opacity .3s,transform .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#e6a23c}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#f56c6c}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#c0c4cc;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#f56c6c}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#e6a23c}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#f56c6c;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409eff}.el-badge__content--success{background-color:#67c23a}.el-badge__content--warning{background-color:#e6a23c}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#f56c6c}.el-card{border:1px solid #ebeef5;background-color:#fff;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#c0c4cc;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:-webkit-box;display:-ms-flexbox;display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#c0c4cc;border-color:#c0c4cc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#f56c6c;border-color:#f56c6c}.el-step__head.is-finish{color:#409eff;border-color:#409eff}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;-webkit-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-button,.el-checkbox,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#c0c4cc}.el-step__line-inner{display:block;border:1px solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#c0c4cc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#f56c6c}.el-step__title.is-finish{color:#409eff}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#c0c4cc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#f56c6c}.el-step__description.is-finish{color:#409eff}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:-webkit-box;display:-ms-flexbox;display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow:after,.el-step.is-simple .el-step__arrow:before{content:"";display:inline-block;position:absolute;height:15px;width:1px;background:#c0c4cc}.el-step.is-simple .el-step__arrow:before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow:after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{overflow-x:hidden;position:relative}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:0;padding:0;z-index:2}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#c0c4cc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{display:inline-block;background-color:transparent;padding:12px 4px;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity .34s ease-out;transition:opacity .34s ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:background-color .3s;transition:background-color .3s}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity .12s ease-out;transition:opacity .12s ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item--card,.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#fff;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active,.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active,.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45);transform:scale(.45)}.collapse-transition{-webkit-transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out;transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out}.horizontal-collapse-transition{-webkit-transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out;transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #ebeef5;border-bottom:1px solid #ebeef5}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#fff;color:#303133;cursor:pointer;border-bottom:1px solid #ebeef5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409eff}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#fff;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #ebeef5}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0,0,0,.03));filter:drop-shadow(0 2px 12px rgba(0,0,0,.03))}.el-popper .popper__arrow:after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#ebeef5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#ebeef5}.el-popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#ebeef5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow:after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#ebeef5}.el-popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader .el-input,.el-cascader .el-input__inner{cursor:pointer}.el-cascader .el-input.is-focus .el-input__inner{border-color:#409eff}.el-cascader .el-input__icon{-webkit-transition:none;transition:none}.el-cascader .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-icon-arrow-down.is-reverse{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.el-cascader .el-icon-circle-close{z-index:2;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-cascader .el-icon-circle-close:hover{color:#909399}.el-cascader__clearIcon{z-index:2;position:relative}.el-cascader__label{position:absolute;left:0;top:0;height:100%;padding:0 25px 0 15px;color:#606266;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;text-align:left;font-size:inherit}.el-cascader__label span{color:#000}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader-menus{white-space:nowrap;background:#fff;position:absolute;margin:5px 0;z-index:2;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader-menu,.el-cascader-menu__item.is-disabled:hover{background-color:#fff}.el-cascader-menu{display:inline-block;vertical-align:top;height:204px;overflow:auto;border-right:1px solid #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:6px 0;min-width:160px}.el-cascader-menu:last-child{border-right:0}.el-cascader-menu__item{font-size:14px;padding:8px 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;outline:0}.el-cascader-menu__item span{padding-right:10px}.el-cascader-menu__item--extensible:after{font-family:element-icons;content:"\E604";font-size:14px;color:#bfcbd9;position:absolute;right:15px}.el-cascader-menu__item.is-disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-cascader-menu__item.is-active{color:#409eff}.el-cascader-menu__item:focus:not(:active),.el-cascader-menu__item:hover{background-color:#f5f7fa}.el-cascader-menu__item.selected{color:#fff;background-color:#f5f7fa}.el-cascader-menu__item__keyword{font-weight:700}.el-cascader-menu--flexible{height:auto;max-height:180px;overflow:auto}.el-cascader-menu--flexible .el-cascader-menu__item{overflow:visible}.el-color-predefine{font-size:12px;margin-top:8px;width:280px}.el-color-predefine,.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex}.el-color-predefine__colors{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409eff;box-shadow:0 0 3px 2px #409eff}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(hsla(0,0%,100%,0)));background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(transparent));background:linear-gradient(0deg,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,#fff);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,color-stop(0,hsla(0,0%,100%,0)),to(#fff));background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,#fff)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper:after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409eff;border-color:#409eff}.el-color-dropdown__link-btn{cursor:pointer;color:#409eff;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409eff,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:hsla(0,0%,100%,.7)}.el-color-picker__trigger{display:inline-block;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;cursor:pointer}.el-color-picker__color,.el-color-picker__trigger{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-color-picker__color{display:block;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999}.el-color-picker__empty,.el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#fff;background-image:none;border:1px solid #dcdfe6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea__inner:hover{border-color:#c0c4cc}.el-textarea__inner:focus{outline:0;border-color:#409eff}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#c0c4cc}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-button-group>.el-button.is-active,.el-button-group>.el-button.is-disabled,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;line-height:16px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#c0c4cc;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409eff;outline:0}.el-input__suffix{right:5px;-webkit-transition:all .3s;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px}.el-input__icon,.el-input__prefix{-webkit-transition:all .3s;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;line-height:40px}.el-input__icon:after{content:"";height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;border:1px solid #dcdfe6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409eff;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#fff;border-color:#409eff;color:#409eff}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#fff;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#fff;border-color:#ebeef5;color:#c0c4cc}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:"";position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:hsla(0,0%,100%,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#fff;background-color:#409eff;border-color:#409eff}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#fff}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#fff;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409eff;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409eff;border-color:#409eff;color:#fff}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#fff;background-color:#67c23a;border-color:#67c23a}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#fff}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#fff}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#fff;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67c23a;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67c23a;border-color:#67c23a;color:#fff}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#fff;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#fff;background-color:#e6a23c;border-color:#e6a23c}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#fff}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#fff}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#fff;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#e6a23c;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#e6a23c;border-color:#e6a23c;color:#fff}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#fff;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#fff;background-color:#f56c6c;border-color:#f56c6c}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#fff}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#fff}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#fff;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#f56c6c;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#f56c6c;border-color:#f56c6c;color:#fff}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#fff;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#fff;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#fff}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#fff}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#fff;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#fff}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#fff;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409eff;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group:after,.el-button-group:before{display:table;content:""}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-button-group:after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-right:30px}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409eff}.el-checkbox.is-bordered.is-disabled{border-color:#ebeef5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#dcdfe6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner:after{cursor:not-allowed;border-color:#c0c4cc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after{border-color:#c0c4cc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before{background-color:#c0c4cc;border-color:#c0c4cc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409eff;border-color:#409eff}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#c0c4cc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner:after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409eff}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409eff}.el-checkbox__input.is-indeterminate .el-checkbox__inner:before{content:"";position:absolute;display:block;background-color:#fff;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner:after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #dcdfe6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409eff}.el-checkbox__inner:after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{position:relative;display:inline-block}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-child{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#fff;border:1px solid #dcdfe6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409eff}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409eff}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#ebeef5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409eff}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#fff;background-color:#409eff;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #dcdfe6;background-color:#f5f7fa;color:#c0c4cc}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #ebeef5;border-radius:4px;overflow:hidden;background:#fff;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409eff}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#f5f7fa;margin:0;padding-left:15px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#fff;margin:0;padding:0;border-top:1px solid #ebeef5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner:after{height:6px;width:3px;left:4px}.el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside,.el-main{overflow:auto;-webkit-box-sizing:border-box}.el-aside{-ms-flex-negative:0;flex-shrink:0}.el-aside,.el-main{-webkit-box-sizing:border-box;box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;padding:20px}.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #e4e7ed}.el-timeline-item__icon{color:#fff;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#e4e7ed;border-radius:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409eff}.el-timeline-item__node--success{background-color:#67c23a}.el-timeline-item__node--warning{background-color:#e6a23c}.el-timeline-item__node--danger{background-color:#f56c6c}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px} \ No newline at end of file diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html index 2ef6362ba..c31247c03 100644 --- a/priv/static/adminfe/index.html +++ b/priv/static/adminfe/index.html @@ -1 +1 @@ -Admin FE
\ No newline at end of file +Admin FE
\ No newline at end of file diff --git a/priv/static/adminfe/static/fonts/element-icons.2fad952.woff b/priv/static/adminfe/static/fonts/element-icons.2fad952.woff deleted file mode 100644 index 28da65d498a0cc6cfa587a02640a6e7ca85ad6d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6164 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 M^niCa<;cVTKU1h^ApigX diff --git a/priv/static/adminfe/static/fonts/element-icons.535877f.woff b/priv/static/adminfe/static/fonts/element-icons.535877f.woff new file mode 100644 index 0000000000000000000000000000000000000000..02b9a2539e425a7a8c244faba92527602be76212 GIT binary patch literal 28200 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 diff --git a/priv/static/adminfe/static/fonts/element-icons.732389d.ttf b/priv/static/adminfe/static/fonts/element-icons.732389d.ttf new file mode 100644 index 0000000000000000000000000000000000000000..91b74de36778b0ff8958d37d07ce70fb3b26f50b GIT binary patch literal 55956 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
%#5t+7yTm^Z{)9pPFdh-)p? z70Lyb71b@_PUHS~9CyvfrBIBY6sik5TZ@D3`-%{avZo>tk4%nDNlxf(>hQldU@{F@ ze6B#R$59h-4LCf;$#i8BOsn$trrrtrEf(C;i3_~}x@iDw;0ZY^`-c@CBEkZ3AfPz~ zTh$sM^$+)VKRN)dG~vd;h{`d9Bu=A_&^a)ugxH7x?g_?KA39Z`gQTcBOc6MAkyTMw0?i2G4Ox3=#$`p!h`_Y`L;Hvi4>H9YH@*6wq=g0d!E$hD* zUDJ1Iucc2L{Nl{|NW@e>b~R3zw?V zp;DWxuKb-Xwua^g+m?6A>z%gJp{QCKj`?1^;e2i~8IP(~-lUsMdJ`5DdektPc&}Zp zXexjEEACjVQVspUS6=S>K}fBP#oS+cyS%AFwVhUsm4om-L7Iu>ZqOJch{=Ihz^nvT z3i~I*uPVYArIbV}Fk0ivdqsc}JHBX_$tk!(g~3eNa22_Nzzg zj|?;fP%gsZ2_7jxhWXu$I6;@y5P5sVA!i6!WprnT96%~uf+GjGQn>9X@+)YjR4jZ!)5kD34BKK9qOKpkC6^i9 zA3`mUdLi@pgvux441?MC3 zkhgk((=V(k4Qqpqj;_XOv>MZ8t{|pPgT|>!{ypivq(VvLjlFGwnFCe9$#dG2Cp{(A zUgIs3ctut4*mBbEk6^aY$8bzOoCiHlEp{Z0Tc&qJ&3nBe&V=h~oNO!KD>nY6i!0xk z3jEwWe!fP6i)hT6#xBRr&O{nPrjRB35Do5rZoKR)r>hizGei#@EcEL_ULxq%BisjP zauGTRf&nBuV4;%~C(e`MxDOUMpZLGX|G)*$!PS}?Co_4U(&)Eoo=(x%gF^hth9NN{ zIS~9fUQY7v{Lm+4C{vXAACH$eS_5y?P9eW%H#`IV@L!M1Ma5XEIFCNeLW@F|#uAvs zmkdC~1})<@5>I^T=Cv5@qhsS|G#+GAG9rOvT+M1GGp? z(q9fIQo1w61lh#!rnW zwG$Osi?3YK6h*e{s_rOmP~ML99U?sMNo&=1%8ES7;`5x=#@^6m?Sk&L-Ib@t8&H$S zR)JPMvt>&{o}IX$?(4-3PCkdX)qB)tv^?B6K65n}b9gY>3sx%W&zSlTKG6JLuGLYh zI_#?5=5+%Nzhd$s0-%HcdZO`)vc&iuFAaKO$(l@VukFZ3c86N(;Azx7{6b)=j4~|Z zb?JAt=ohqR;7gwrvs;*PIwp346){B9v7{lZ<8vgj+zml+L16R`^i02?uqd;hog*MU@HBR4^4R?frnN{O_yUX8L~fs{*oUk#mR=4 z58|M^Um8YTMf>5R{fDlqSe_bz0*#Tt$-Zjql;&2`N6$b1kqO&fr~JqrbmKn?ao@{_Fw+DR7lgv6sk(OJ;S6o^ zbv2szPs0V#*h7~Gmv6iO$Ey0q0}s5RHiiT1(89gV6O=!`@x~t&<^9*sKe@Tp*=&0G zh8tfpnO?fFcSmdOvuMI=doG?a(u6!N*4iBwwm6M@(U?FFqH$=Ivo&nXCy#&uB_BU> zKc)&#c*mFs?P1y96|EpE3IZaR5qQtB3u^4kk_4Y@+HwfLGbzi?3*M&A^o2dQ{H zDb4&_g%~oP&5P#ZAb{JcSuju~h4yh*7~wL=ZbNxl;2ANFLWl-3J8xtO`HeFqzJX{u zQAu*OTHGQ|5kP<`F@GnmKe&_cl&Nt8-+A?SO{VW&ZQLN!x{f;hj{|h}#}{o^lnyu?Re;4%`?`u`(Ngne^}R9Tif~nmrTpP zL3$E8DNObU_eW5#1aYaVv0A)X+JbyuRM#XX)gA#EaYWh*i~IyB1d*>BNoLk`*Mi6L>AKM?ZN{J4cxl`EzH2(;uHNT;WscR^-J! zV(ZENPbKk?dSU?OU(*nD45x6*4;T(XaCsv39L;zQl^@K{5>yXeiI)&9V z@^4g5t9Dx)_(_gZg;n}rt8e0sk5+`I&6*Z=I$mq(ph^1%tMBnXhUKX%e66Qq_C5*B ze;zDXyw1kb4_q!j-QQs8w|9i^sctk@`gl4rwXtz(2bu37@jO(}x;$@j3%k2G zhI5(-s^Sc{;!lim{9Qe$+C?;1C2~b^=ZV4?2jMLm-7LzQuQ=AUk9Tw;k^>R5h~rRW z__^0ZoA#^f{!J;dbQeGWc2&LoJh45!<~KF?k4;U@-eu~z@ZGZ>KWn`FtIwSq~R|ot5{2Cw2YRP2gZgubCgK#HDx(=O%l4JsUjWBS!M4v~&$lWkr?@|ya zlLuFn3hBk9s2taMqUOy+`5ea^iXNbKFND{Dw&XV{cwL0A>Ztl%brQx8L+D-P&-6nF zjQ&nW6zd@&vlw&sla|BKvnL!3C(W>FsYv*l7shWY^_dp>w$3o_oUzrn(Bv!St9f0S zTm1umY&rY+&l@*-m2Y`-i))=TTlvP;na*0Cn^sk7{B>Xf=L-h7v$TrO#~c7FS1+~4 zN+L6s7!PP#ddq}P%(a-XCC_iD+^3X`u)65iJqGD_Pz&pipl?8JLE8j<^kWzSa3P#8 zk$ft64oj244;b#kDj#(y1XhD6U|@4$=d!TqBAVNK7k(roq4?YxsjL)lFR>GicaSV5J980Y)Hjcndt)VXQTQrK zguW$(WARP!Mo58!YNBOsRI$btNg&KQqhE0dl8DT6j^v*Lr_g-(g76-f361N71c91K zsqV^vXvDi7nP^s33EA&v@2k7y7-O^ z4xKceslgg46#jw%s$^55bENf)>t|Te zKJ>NvF662c5;X1hI=R}kw)J>pMVXO%TAA@mX=&$A?WH*^1P_mS2Kv@(yhAh? zPtw@~Kmkcdza>JokI+uH{Oup4?)TU1ZVZ-BbyV3d6c{jxR6gFqla3ZN%ZL#QfQ zZd8D*iJnhWOIU4N{0m~MrcD-Wsja3y_i}xWtrYQE`D3Lwf2`R`JoTj$Cgfh8Frl>G zQ)0^>E4>pYxI;KTl2+4_(xju6sbgPc92k4d&o>U_pUl6BpFif!Q4NYxE65k>w`TO) zTGRw-aw~~H^ioLoqJ9b#Nef$HHD^yO66>N`AZ&`?{+RZZ%APWI@;giIua(G^W=meP z4^x&g4%S)InTMJxdo%Z@()_08c+cj{Js|q{N~i5T2MlQ}y~BH7){e6L>O-k~%rfQ8 z3eUfc#h|`BC?a<~fVjwJ3&#ez0{7+x%9ufIAdM3^tWI>24;#Zg1WJi5_KXxwUZ$u5 zEu?C4R4;YBOh0)1DGpG@Xh9Ql5TtV{QP3f1sn7|e{J;s$5gvq2N~7#5W+^wpGj{^H zX{P99h%GU4Nd}fbgP%J{6^1kLRsOzIi}`SDT8m22NJyqdmaxraq)N?Xq{hw^^dWuQ z18ZawMj|0Sgf$)}n|&IOP+lN6@kI!fA`XF3LVg+i-WFO!$zVVYVE~BIP|^_20zD4V zcV(c)Fqi1^S^9|vMN8qnG|-R8q0CEhK1D7KyT%H#{QJlsjp4S?_$_3!)F2}}Bao$@ z#@Pv$lD3Jd^gDC>;rv>ntuoD>Ou51@0xAv4rc$4pQanyW!{J4b@@tmo{ymgm1dr!a zwH_eC?Yz69)X*Gmw^P}MU!zFpb<7iJx*$+|Bjw9C@@)dg#GoEAfQzAJ--y;5$#Y6g z;_G`PdLg6A4xLL;kWY@XX5e4d$kH`MqaV>{JCGE zJ!8j5>D%IlJ6=|l7j(!BdgA$WWtvXEPIsscMR}s}6_N)@a9Kb~18&9`KURn->VN3| zmAT3RtdC`l|(ME*K=)AQd^8g{8jwM=2Zp3fkd^)W% z8W<*-$>=cxn>mIvsob!Z7o8AoX*~B_iic9E6pgW*fN$xSvnGi(vrZt%2_+Q%HRbb4 z2m-%{*N42%oM1U!@ps$$eMsRL*OOcf}YkFbsMfPRJXM^q?Jw>=_5 zD~4$0t6iK8P2Zp>8>Ua+aGTVgD(MG^{?On#JLKF?1I&zo8Dn@@xnwg|22d_}wg|gP zzgZf5Yt7rbBV&Nv6T!dZtqgOqgU>(i0Z(bEV}(bY#_q=cM{P1mU=3lIxK$0EIE25^ z4Q#ezJua>CLQcgxA1Bo7)SJf5;P_cbjg1j{iW`ec4#_@s{PqO7*K$l5&HU(|;Dcj$ z`h>kO37#cFuNh;sEmkr)R4W4vIG)Xj1Ho!c`Ua^@Em)VO2H2yG;t^o&635Z>GT9BR z;5JOv11u*+P#6rtIe#)p>)wjF4~SZz>d25EEU!x;pXNoOMaz|?xrdcQ2pW7D0x4j9aWF2CaVJ=4;^;+wKv0 zg6vz_{~SmIl%0E z)c;7Cgj4!oFN=&~(*74^_>_4^=PTlO%J&I0K@bBgVN4y&D_W6~#=y{um`q3$3Xf-Z z7$As>b;i2`hfoh7?TJd=Tm`+3i;dM$O^a@dyob=7T~PfTeoiAx^>*;i8t{fyDqwP^<~yx;u5n3F*Ahyd=a+nw1>A>nNQP)R$Z|g@2Gw? z)D-tP=~DQs1Dj@BD_xAQ!h5g~{ueh0gVK7qV!TV3ly9xPVCAx$f+fL`V!7H`Z!bzT_`vrhzwbCv2AYB4IbqM~noxM^)FXl?D zc;eY7&+pk2GfA1dM~LBKA)1Z$SthTGs1Ky~raz1C^O(PL^F07+0q((doTRBNIU+*_A|qT7EOVZ?i0%cwEKc4vVn|AF-w3a^T|K9+hA`lPC~KsdIV0CL0j-KOJypSD~BStv$e$S zk;(@mv{ME(y^Qgd#yJ_a;~C5(ZjT&ae2(HR_!dR^>=8ovizBqs&Rq$XC{0axu5q@N zIa)w17F1@zY@d0)SP7|s6+@(5av5Cfwioad9G})0VAQ&pYDg7|xYl~?t=91yf?ipd zc?mod%>e&SS7Ab?v{aa|FOX`^fiqOXtkVbvTrGhuvKjREBkqun?xY1N{YllfMCR@7?6 zbt^CPt@^yF)ruFT#4EDY1(Cx~u)yWAwqWrbEdKO?$Bam&Obw$s7l&pr8)BU}?CIH2 zVo07xF+kI2FqG#dr%^8vj3va|P42rX>Fx7*KY44ho|}NZVB)Jh!lv?{yzX|tz1RO$ zCSswd?A|14GNRcTS0=24&Cg!L@hYwROt|t~V-Q25s;eIp?F^ zRh=a7KM+RzTs<@at>Jnz^J8-sOcD90GG4DA?UO%vvj=sTTRl2=@905UC|53&%W%(* z-JPs1g>Zulx3U^e2c-RLAke$5ms=((D%b5r^$~{!S8oyX&6V=97(^2=-dXM7^UV}& zn8WBSDi>f;2bJe}1!@ni9jjc0A1zV3Y3wqn*5_IIQ z$2Bl>6vuPxceLa15!(&@lCWsULFDK^kRQktb`I1pP7&E<`EkXv#Ha?z92+}elfuXM zAtiRBVcB+2<<*={Qk7ZSyK`r(B`~yQYo`0K`IgHbYn$~x7|NDvMy+ETCr~o z24~jVpjrmDSbUpL`-L>jM`17$GpAwdTdjrytp31MqpTKrBwkWfW4wZfP6hE$Y1~xC z1%O%PXm0$@<2r3PM+Zm+Ov^%V&h~A5PKUIu;toVVF1IT-B;*UO26ll}6&IvP37YNZ zrQuX{@!GPe|4NN!vT9TRdl>cmyy8QP+K3ZALqGIxgM*1=qm zG`J+{TL1;siK$6Z!h)%$&Yn-zd62YH2`fDASLTmD*FLZ9#<|4oU5s~dV<1{jjy3E? z8J?hn&9&AGEj690t-6V~tK9T4^Xa*)W9~-Uee@$O=0WKfOk9ICoq6v~>|EfcWXng6 z((W7Q9N9VZ>7PgkWa3IU%8H*}r)}?ECu^G%MqHL>f%}4eGu~}{_c|UyvEvNj@oM1R zYg(V4Uu0N<*VVxC-5~kyHG8*uaG6p!!s7(Xa4bP>1!ZD%)dsqqy&J9dMv?fScDW46T!rUC?PqSXoTJBY3^Z7XW;-E6#XPdd6cWy zO-m{ZWv)A4z~XdODPtit%(rL(Uxh=baJ8t0`w$3N1X=KTd(e@|)g>;8^`A~0`oS6- zevM0Nrn~hM5Nc`Xpf1r@y};Z>-{pJevskG5Bl-1>;^2XW3V)Y67E~-YrvA4Cq()O_bQC_EDKk)FD&(88gd=`j2PlRo3;MfELP6+IT4}MY) z?Ra4OmM!M9SNziz`}WbN2hEu+TX2hZ_Vt}JHDJEN6J6?$n6ESsZ(IX!>*_t?x%uqA zeRzfLA2j3JAK0;F3++U59B2IsI};Hvv^4tGY#M4-mTVANUvr_g_AeyCdbyXG9y7su zlL=5R>?FDac77PxG^k){S&fpbINUJ?ITk9n)PK*7B-zL!QQC`h=QeExC6@(}8_J*N$Um zm=<{UE0O4Oy@*i+lRGHCRsGm8p{Xn}l4(FP_Ls^D(ES#Si=Y=-u3SeuTiHBWrBm)fn0cJp}_18orE@ON6fF=ZSW)%uSy#i7lW@!A$& zdVKKp&qlbd$QwKdfRU49ZgA!Ajz?a92-H)ZBbEh!Xi=>7!sT>NeE>PzwWF!RejbDi zQ6IH}()_f=DGeSN#&w_xrVw134qY!g8!8_iJPdSKBOR5vgLE*qar8#zOALrJV8DHU z78qcv3@`u?&VjQ*;zDdMz+MFGDL6EEHhBCTdlRb3&g_GZvzE{Of0lB;FB`lp`~eyT zAF2N+TCley%;jKTi)Ll+=^6$p@C#%F{L;9i8R|>RI?x?2q86UvBjhAI?K!)kE?PTO#zLkxl`<5+iTxT%W!Sau_uZBIH zrL4OpcUrzMi#4IVQ>Qex(aFl#yv9b(7NhYzzK=tGBCKT_wExyHJlisErKseDa1 z@_6MeE+DFVD46$#;2nv*E+58Trkrw%#Mm=VXT(A~@(Sd92$=C9RAZfxVk zJey@JHu$K9|9|eIFIi$U`GPQ;2_aNs+>y+sglJgjc>U%3^-=M3xqA>66)f3u24Q(E zf>X&5Sc<|Ac+pPWF~?CF{>$(F!>CFEUv*Vy%x$1h7NRkB{2TH&^VvVxy~n?`54d*w}yQ10(*+u2XxT z?pPT=CpdWU+Vet}4##^|w(WS|o?g$Yr#Bo}yYi}Q&WD_!0MBtL(*k5^_O_?A2;5~= z)h?<%m%27ASB|j~jP+nD)|@|GAE`ZsTCNKcY3=u6-RVC7mx406UTRtk^fd4-~DkfMBXKPDl|~EbG`J4 zw2U4GKK5Z*UL|4xVzd>yFl@_V4V`_{F5ZpC>y>!GIx@Df)RcO44WoLwW{#r0!G}0>TFC!MjhvM;2&1O?|~K%|5CjmH7^!k zX*a9C!ODw*8Ow6+-DuSt%R6veb;I)B*#I-f4>`|beUh}_S<+Vt)?pn6%K9r22cxL! zvzC2cVwxmDndPOR5U|g@P33CZQ{oNz9*0f+Y)`n#pgi#IlE$_az-aau2XyYk@WxCG zD;1+4B=n*asNS}bcUtwTQh`ZSu3Xd<3^r}U!6@VpuL=7JuAjH@EnNa#4}yc9IPz$F zbGWrN+}!bK;RFx{W@(~az$*-rQWeN$;2JPuQWXlb#A+@;NGKOU>K4tFv@r0Ucjlep zd%1T&+F<+7zMr~eX_U(HH$Uj=YBqn*dVsgOM!N7nG)6QwRO7r>EwOG%vEJifsRl4F z>m1zyR2~}|8oOJ%^byx89Ls>C2kZNMk}+F63C_@h$txdTDrT~S*k^1hdc|n=r!j9= z$a9M)>>;P$bFN>j_2^jnb<7j$^xop(hv$0O4o~)%ET@0@a>Pk??BHM*3^GQU=<197 z`V5Nn&dhj2UAQ)_^Y~@Bu4wZk)^nNG?^)M`RCo_{K&N5td>nnko{>-sR;b}0two#B z@=n4yf2KLLs|ARt7`tBxQ5jOWBb2)=$^+^^|5;nKe>PG z0R1i0pnZLt*W9h;WSWBqbFv<&Oc~YjL%Lq8D5p~x&YZ>SGiD69LO848P2*y`)A?FC zxd$%79??9%b9cHw)3EB;A_J0w8B!qK8#u%L5$f@JpYjm(E%KPU{@`8Pwf&C$h^;|v zTjoOxvBR19A7*q6m$o__xc@$;nfrp_;9{V@FJ@~Wi8P`Q*f%HRTdUAs*OY9r+SXvp zrp*IT_Yc4jQ~2U^wmCxRsSxa(F>G`C}2?*@}~z}y}Lf=P>&;oaT=>f z0Kwv>thyq;-qE9m)Rt8(xb}2N_bqiLJ=Nay22`U+p?;z+*Z~#*S2Vp z0)z$HMvw=30OnDEI?E;X6_8~HxtSN>!1=NB&(DX)0%PwP@IW6}vjMcS$10n=%t-0V zv9Uz3b^W%rJ)Lbk_CXgf>a+lTUl?I8&p8Q)pP)=hoCLnUlXa!txXEiOsJ33}p$yROXZ-qgZI?5ARZC#SzZr!H4Arnb1_qs$MP&d_vJ&KFcYv zqQLkhR&O>!{t%;FsQzOr2kbWUiE{8FiGhFNCe**}}%v65wR{D-_M-)TgBFr-!g;A2^;qSQz_lZf?7G=8C_(c~515rmrsCp+c*thTnVF@QShi=ElAYg6BUOoB4}SV9nIs zA2Q}uU3=(eZl)@Dc?tO9;u#@hFt2}wfVFb;!f2-!Zu`7?vaEjow!(|*k*lvhqKYe} z*S&n#T`#Zu8@i`@3lFS3Ul#NzxH6=1^gA%$IpBca2)pRe{hLRjhu92d5^utmqXyW~ z$zAQqWc#ksW1|NS;8GXM)mSyCNA>;X{rU&TKNt++QX4V9SYs%`Jy;#9oS4VM(2+zp zLfCM^@PjnQk8-J^m!QzOVemNg(&lf@$F6{KC9E#!=D)~WzolP}k8@tgu!tW%`GrS$ zS#d1BLoMgT`Z~)@EF)>5Zq*X}U*z6?Jj~{#e3>lrL`Il~Qb`S$O2S~2FKSl_*+Y)R z*ve%{zk|%ps%wqt5T0}bDXIYt%21fSstYT+x;AumyKOhTDul&Pak1;Zt*5MeAsVRgJzs+7jZ`B(+$Jds4e(}IB}R}>hWuz5ho0-!AR z^Js_qn`??sZ1@De>Wb=a7$%sDr~YBxXYi$h+@^x!7iH(LB56lhC1L*!%?|n_?(wFq{hzwGg0TC=wH>+{eT z1PzzLJ6H~CL3y$m;ex*#ZQ(U^bzI~*4u}Zx9c-vrE^$sJ$pg!*&_uPD>h5B{=@j4v z9b~{8H&lImya>j{dmYS$@o@<23UfjJ$oIg~Ag5#0>0=`&9&<;%*f=&0x?=q~diGfL~z{2sUA6zGi5PjclPgA|O@*@FY{qI-k~ zEx|0UIAn;L=e;BJG0)JhArI{_pArG{5A>V}d`vztw_6FGGq=n8#nrvNt95Z99Ko?% zc#-~U$1c`@SO4H}sL0(6fS?JyptCe|EtHDYzDF9+7xppq2@P!b2>dt%Ft(Mk+ygB+ ze~OD^rPY^JE4?MI3~7NkY(mqz#Fxi;nC0*IB4Y-!Ko6iQq61OzBE7NIA8d<&bwD;$ zpj)iGg0#vKSGhl71dk?^%gobMy(oBY*^(ba7=6!_e_rB+Or>*TBZwGtS>!=gtPCi$orTn+sZ@=i6f7pM_MZRDoUD_D*36yjQ zJS&4QSMA-Uc2%-1!K{EGi*>6zy^$T$K&v2+ay)Ald&BsY`EvH!sjI@+oEav3tzQ9d z)a@7AXHhqnxJMY~s0uStUI(q&{Q?x}s5o#i z%vLqvdlntVES>bJjp~;+PC*lSO2I`P4<5*>YW6^|$%loIwl)ZhZ-l?yf zSEE}yRcNGetTk4sRi|{6Dvy81Obm}PnsYNSP_mC8p2%+MN3x}e7U}5eZLb__@9pVO z4^@t>IIpLrrRTgA>LDw1k1r7D2n5VKyv_Xk1rcrb${+O~dpgX{_TJuhdaVOal$!CT z*@-usIYh5<=!s^p`4W=*DB=q&g}u!?DB$b#1_ItrU*J;+a+*%BfF<+j-)lE%?9Y8C z+P>L_BWhqXXJ;=Y>_v^8s|^gYBQ2;aU_=M~3@qxL!c536qind&iAU+YJE;F~vu1ag zC0CQZ+1t?aOP6LRZO^0ou8Zu@e-Le5=WDiU4qww9<|~Jf5{C01{Rl7cl!hQnvZEt9( zDTH?~MqU_cc+4qlW5Q~?7am)_5u`Zf%6drD9O3 z3gt2b&&C!o1%x)yWD>$M09>W<4>mF~u30Ms`bnfvOFUgffOLMurlPfB3>LD^I`D7@ ze8<7o9JIzJVU~#)e13;;$US?FU>{{m292<%i)sobv zSH{Kf^ZC*D;N;`EMvp_a`8|Ds{ZDQg8MyL-PwiC6ZgV^rfTgg#(Mg-UcK>@#llJd& zYW8#NjgGF?24AZkmI;u`t-LmH-hX|CY2J_<-Rp8AQ7GW@Y#O+7|C8I+x`s$|G}@1% zh!sxF_8oU4t;~+XQ5TYNo~^!fTf3m=#-~~Nx#U0yx8WJ2P|iB#s1-)%Dvw%W72&U0VGZHut*{N@ zA6sENY(HMN!VcVj#|pcZ1LU;A9;KhIbzhh@qIqL7JTV`R$I_{(bSm#Q5=PQU<*ziR z3yEmfidjDgjBGBRPKAdCH&}NrHd02mnn&))^l&~u6`snbli`bynUP4O!a0Y0i?`gfiNy|3ZoMSL3s6PE*80Ry3^~CQ;wjVVU(ChUBdWg zkxvq#i>#V)P6>p=aHz=7u18)mq#lG(KEIWLi?{XotG1+?eo(Y9iH>GjRD9gl?`c2O zPAX|+!|JXB8Uq(KkefWv9{E6Berm$1TQknoYo#^{V$fQF^c}R4R)N{G+q*DKV0x&R z)=(eyW4e3}t)+F?m2nNsejnHNoXKkUav<*8_cff*-U3cj;Mi1RELl(muMBE~Cro3VJWSkFKQm(^a$|Ho^z#YWe^jqQi6zT}#)|2Qht( z(gek5k_?)nX_}!pT~D)=pd_UzO*mhRvXrAd73c`f(G4_DAEuAcjdT;;Ot)a7eU$!$ zZl#aX$LLS#HcW=^ppVm?^a;9)?xsJZd+1*JbNVFRM}I+|qEFNP^Z@-O{TKQSJxHIW zhp0rKqtDY{(Zlp#=@|Vt`T{*d|D7JCFVbJrWAr!lI8@VLqA$}Ebez6IPtsTEYxH;Y z6g^FUPhY2RU=r|6dWN2*Z_#t~ZF-)*L*J!;pns%)qVLi7=>>X`en3B@m*_|IWBLjG zlwPKPrdQ}^^grlT`Z@iA7U-AQk^efqLI0C}MgKx?(*L4=rTQfuBk*i4! zsLg7N+N!pxL1;f$sO@Tp;*ZCSNDSnijAYY=)MV3AJoljj=-QP?Clc{YI^)Zv^U-`d zlFMh~nVc&bPs~R0Mzn!nn9RmgvrZ1-jw6+6moX-LTuI^OQds# zZ!!|iX47-Brrv6d8{w7@YJ!vLxs<0Sxl4u%8Ew{>w-r#lqmW9ZW3x8CX!&%e0biN5 zi$k23UBJXP5sl3{CerzQI_Z@^GM&eYh+>m~cqGLzv~jQrRW3}IU_RUv_kF~BYI>$l8wew4GGSgyT&a-;--5pj_fn( zIU{Qa#>8fv;u;yU=i^Bu>xp8lOLB>^S#L6mHl<_HJcc^Ig!5wD8=ah7jI>r$MdBDc zvq|wr)8b7FG3=Q{G-kMfPOTG(H)bjptqYY&tVD9~pAUfIVqUMiWkP zjSMy90AEp2Eg6rwCZaiGA`0@zrDHK8>jJjsIqt@TSwjR}xqLJm0j>CA>CAj&G94@M zXzpREisV2cM#`6)ivs|Wi2}MQrA6aOTMU(Or6Nf;~S|NKQDWjAS%n*!W_fF2pAd+l-OO*iyz^ z&X${rXYBcGAvWurh{xsuwuVerFwN++?Dj$`@0deJ8F^bQ9Z%Vl0K!QHUp)GkNoAu%Ub;17@DZ`*~v`ot}*hF9nC}Q%I3x zMxBs=YseZgBYp&L`!n$vz`KYxZKuWMz~s&qfQ>-x$dIcVv?0@^*O-jwtLW9ZR6ryj zo%T&e^HDI2XktDW&oyM?jHm#JTil;WGyY)g<2HDb(dl>$qZ=4Js+rE>CdMgr0YK0o z(ldhCC$fdyj1ydB5}4samqYYTL|wU9JO`GX^BzH;r_ozr7Ey=f&(3H*pN+=yPIPA+ zL!9fw>2#87>=c1`3P={s#%3JyEpI+LYeeUw^AYauLWbG@u#34bhZ+QsV;GWw32}(X zS#OniBj7nmCn>q98jz%EO!}5?fa3j&G0C`=;*y4)3(6xbubjFM!pB0rw6ftdIuaC78`*;f*LIGsWmZ$cJhE}M%K(BQVsczgQiL%+Y~92lw@1hAU8AE z10)C#1Q;L_AUDZHE&}9g5ajb@Zy?_yzyGt=swz^{p}TFrn3+C^WYwy5c+RJ_Dt9s* z?@mriC(-M}UjNPav&r~yeZ{qpA78x8mky6+gWQW3+1}w{_GRHTd-Lw>b+)^AH15xb zlW{I8%nRfEY4&IqWoGl~us_e*MGoGc5ITr^DTDcG#bci-)^= z*#h%Qein~rz5OU#I37kPcPH<<*>a|wsg$dA`;#s3)I1u`yZ`Xb?ES&($tdF+t}ivr zygL|;XY1L)e16znTRS-cn6=Vmy1!N}m&>uU9B9q8>MEw zGO%COev4)l#F*92hpEVapvGx0+#YOiPoiWjfrh z7h9z|eeyuH+%8tQQ*LE+zrn1VjD8lpaUG#O&Fx|;gO)mgzA-2yWDV4F4qU0MzvIHw0HdVO=|^|Yqd(LUae#* zol2?F>hu|dSp&gVh0bera1JC|9YMKT?qsT+QoW+l+pT)04K%97N}Ja0Or>G71%1s* zOHY9mgI68s0N-M@Rch5+86IVYbymT!_G3_NHcRDN^BAfw)f@b*f_SK_+$uFHtwE&< z(weP4Q_!g8Oih4b45n)RST|LNor;ad%_^fA#>y>dNYiP%SvAzW+0^W7Oj~3EFF~(# zsa00A$ZDkux&VbJtwx{qGS>k#D|J6=buiWz)d0bka7OSWqwuvsxO7F0z&z^5jdWooRq(k@o(Hmog){(w6)0|?uoTld-^gI^${UIuA3t*Qz# zpp#0y$*SnM2x2P@)(r{)GkjWRF#9n89ko)m>EYT2uKL+$>2)YC!;_5$l+S_zqR65R zjM~f()VAS%{x*#Q1WI_N*{Wn9v#POq9e^=TQ_U-YzHYzlnwT)&;_snG)>XB zg8}Tq`ZAIi?Y92`{>$7i8|_t!;F$-@JXnO(Xw0gb)%u5nDxj)0p};!y(_($}Qf?g^ zH4Q424xD>zEZ*Us`&kjSHrk%XVo)FgOPynQq+O*ggO~skQDmx6YNgVL(LpK`s5W8T zIsgGhz@S_&(t_0&82||c+8Qus-C6_SM#H2MkJfZw0t5C(5Ya`oaa?J$u6BFSU|dWHB(4e(YfcaUeLj?{IPULb-d`V;bQ zwd;M9yHNxNKwX4`%s`6pP0iq3_@vX;uNurETLEnb0YUzfIhE!{TcQk-TgdV{2x2g;$-D59{cRk(=m5pFbxc01@Nx~DC~T1AxlUm6T~VQbPf zm|88PdD?Oso09I0Mi0rSXZ?rSSGH)knm#OmEJjx#$I-v2wpIn93Jk085>V?@HqaOy z6e1mo;cA%{5}FZBS|J3S++sQ%1Socn*d2w!?DaWo>IOQC4}_rq)zEW&=FVE-Cymg_ zu=+OqFV%t#0o%1|(l8iFrXs~|^@c#k)3S|_E(j|7Au(R7S0z>@u)r?8pc^GTQ6{d9 z{}H-zSGDA3x#55KCSXO~7)I$vB8J|>xb{O5y3}SxlA-mwjEhbc`3B;!9wpZ?hurrD zhyYQvkQxBAZ5cWpmZJOqs~#7H+9Oi`A|G{yYNF|krz&yCeUu8=ohoQJ;sn)6j zQW!(#4P++{sEWR72vqk2+G({V_}o>V(0XIb2&UmoM?A`lH?q zuSw2X_LI0)VJ6vczd_~AzWru4e?N+(82zWa8v9-i5ka;678k6Eaz-A=P{W{tMw+!b zqE$W>2EU1r4i+UW(1P#qELxbb$nLgeQd2e^Hh{l{&51e2Q|)SN%iKu@dJE;$u+i0* zWNfX1V74B&Q3ObfOao`E(wa*OHyez~M-zJ#L0^LlaYs5uWLq0%YI3b!WY!JLYdzI0 zG7t66LycmGk?U|eI-uR!)*{=T=3BM5RboD9m0~-s5`k{ZEZT&dMYqf%YpGS6MYqgi z8x_!jy0uK*s&|@2Tc(~uzHXHnx>jnHTW@V5@EXfRf3Qq5#oK_BRWehi#fPLVt5lEe zx=dFVS!5}Ae{PXQ7TE;cZk6s9Hk#|*J>}NvJG6Dmohi2)GKtU^wOZ}1ShL>(RxyVl$#%*TL2c%-=EFffoRTMZ9 zqVv{z7VR{hY3}bds`KQb8q}3^Xe!JPhQg>fwrg0j2+JnwtvXMpSZ}u-9#J|Nn{&4o z`GBGg*Ur&RN9s|+lXZ&-+**XC3U+}TTCR(fznfN(wKN-*ZDbrWNF)TUTF;^o7VB48 zWR-vg`ZN%@$2@dgkNDrV7(beas-KAmxSyr11_z7z<7~iqaG^(nerT1@JQ}v#+-`z& zS=b`vCPas3avyS~xa4ow01Ds>O=@Ux2tZBdt|Jy@{o2_6c1$Vtw{q`l(t(}~QLN>1 zb-ON$o*~tbyCjaQ)vT9B2T0cHbGss?ttb3Nd%|CHUD_kQzYo`!@6~p+|Hb6{yWzaJ zcQhK!`qOAh%rD+rE$zMSd_Hpa*RAkqaeQQaEXV5#Dj-_Hc(pSs5+s6AG0icHFd-1U zEu;{49g|S;|DWHOgHS5{#Tez$?V)5mwyo+*+wlH|P%$2sJiUs!c zIZ{A~D~);&NsCG4{<}gvTPPRl;uOYHQWPK&5f)hB9=@ z8f<|*Eu3H%mZ70jhHSY$k~Y94s1j9RX|m3kN0UF*iY6lGt6CXpwxEvzwRZH6{y5aJ zCb@5{TwSzLBkiXAF+!lgx~!NWS{mWWdPn&5T&y<%vH;9D6~ee>Tq*lfsaK#H+(4<~ zj!@yyhKu9TR>SoXt`xMaby_2OZL4eLytFN}!rf3{<5dabs%Q#{*7pLAd zYBXYW3xeY6xKBol7zhv}e?2wIPOsK5Q503mbQFO-W^^K*!Xb){2uibA6^sZLyT37% z%($+#s}7i~x@jPH5C>AA2!M;^Xkr8jRD>7dn)`-3^o=0lmSx0S4l#No3<{^0;=OLBp{T*zsv%n5c(Pe6C!FNqLO1m&|YMWiD>vWVIvt*uZToD zji&L62*vS=pyinbvhoZC#eiizeJHC68G|8=M=>7)4!ZO4v_}@{lKBD+88z0eKA8~7W|RL3wIb#FtM6=qiwRo7|8IX<%kC5od{EgBY25L)oLS%#Yur0 zxW_4HQY0#9NbFrr%+rL44Mro;YZFNOO@xDe1!FA&b_7d6TBT-4 z!>0#n3a9d~iCD;b3#zTkWXIEXG8%i6=z7J3q{Nj(tgz-Lq+lOGJvSrC{<@d_l0I15 zEL4)NDPvcp%hE|Um`;HlrBhlsxq=|*67ckafHNuRgaI82kb*ejQu*AVjlYT9s5vgX zz6ntKad7`jnE>NxHjj4G4xYR6#TCAvNJ`H`5LLKUVFr*R3l_j~K{+FgSCp{(4$d$K z*qI|LTtJD5j&;nsXaq zO&TG<`l_|0VXd_osuEZ$$`N2)o7oSA|G<&|Za5-+W^*u-ruuGtMup{UaxJ&*8z*qdVS3w>(%t1cAnt`pXvV*@;-!x)s?ciqPmHz>!pt1ea zPhUzR%m>lILLA;Md~tc;rjZf{SSTf;&g8n=^(_Ed!$=`zQrjSe(NYo&m4HZqixf8} z2vWixlyv}aL6=Ag^kL6yS7Duqg5ker`h30lg0M4BNfy!+mrlS3u|I&e!iJ?fgHw#QWjY98ktF8phZ4Z zW-y?4cR+wbR@MqOZ<0MFwNZnOfnTGeVad;>5BgE`7;;A~*wPjh(hUqGM21g2IumL!r z6X$X$zJRmKBg~Ct9Ih~MmGglwCU^-6Eg*%B4_53C}Xr%~}Ty!ZO!^M6-np zAcll3N%Yk#Js;fmA8ISKS^nPvUlSve?LO=-_gm(A0x&qdqHswEFIvut(mkpG!5LH7 zS(DUMvD=6*s)g1;AP1ANC?mlhJr>@B<2Lh_3@QAevA$i}x znZFp9cVOmfX-fGZgUJuq+uaaf0`&^7+U(Jpk^7Kv1`mKu~uwUm1C zpMitQ@GT}2^?A@Q%M(}1tU~uu@CRL50+FSPWtt;ot5RJ~wz{kv!b`BS2n=jPXBO0E zXuenBDzQ5x>^^K}j8Zi#5S@<7mDpFPQS1oa)RY&uN9Y##Nj;ED@e^k)t_(= zhgVjCL>>CTciJHXMzY0`p9HbLYg(eMxFJ%R#`w=RN5m1!&=V}mqP&U_BZ_E5z*p4D zoPn_}=`V(`6)C_t{u)XY0Lxq{BfHRf!helGH)Dwi2@>}uR!n1of4V^wK)<5aPNm%g zbwnM6L47zfa8r~ruKWR`)Jm<-m1R@^)v14fRlW8ntKi!0%?7V0z3DECagpxkHI|BuqxYfch!OHiIxfLrl~oqPizp$Fa|NnO_i8tAbzz+Y3Od+46FlL zF&LQEuWp7hB<8Fa%|Hu*V|3e3P|t=n=wa4IKc-pYb$&R2AEl|VyNGaK11O^3KMWK< zc?Z=LP!#qLK#>)BAyC3iEy+W587KijX`mo_R5?YNq?IO)GOK@m zKy^W+Dokg#GEwv}eXtU$?m#I^OWIDDu86cOT%-A@!ORim#@U zv<~>MLfpw^4qDNwrZ9)F_26#h?66%_|7xjiWhQZcC25EVfaQw(XSM>+zKxY?-#3A7 zhd`+eKujB2DWwQ;NlMa+3p}ymMj!-Ywa!#R$wP)f!c5@&rYeNZox+hoxZsE?I!J`I zT-(4nc2!;4EP;Sjj1$b_Ln*++!^9Uw{kB(#CPutkOGV|wUN~WGHaZ)K4r&?1QiKs2 z3NK^9;V?n@`lRaHRw9>F(vm5$R0$xPk_G-vKoXV4>(%(UV>GcrL~IPg?6S!vepvz17TyCc$`Q%mwDoFKJVf{1t^NAeq3Zfq*oODt{_?}Q%L_aCKAB}W z8%z!lhvWTpEHhlY*e?7`_5ESsv{{J%-w~Zr8d0-IvQ>A>okR5?E6_;NZ8&#wIE;|^ z>nwJK3?cd!_0TvZF0h1`hl!6Z2Enn1jK3&7v@WR%m48D#^wZIXB?uM=iEpSeA{Q1A z!#E%$55-9T#rNPI|ER=l9Tg0LDo)-o)3MU2_aGt`p+CV_YTMk}P!{B-srV0f-%!V3U#lr6mcY`&`|QcWideRt8d%hEhIg1TSFZ^->tRF@$OI!=pT6STOJE7Piu{Nb71bl6tddK$<94Uf!y&9m!MTrk zoD>B}5(x(U?cl^34BS+W006m3nI^Z1W(oiD9WAbv!as`FK)~euJxC!uDg09=p_MG* zpZP1~6keC9d2@+$j!HjCcw+V!Tsv zVryQ+JByJq>pol`<}nNJB$Id?*TbA;E!%n1MiW{zciA|`WU0y&?k%`u=8Mr3*A)wN zAJ#XJY1{ljy>4g^qW^IB-TH*l4+n~4vZ0jBD0FF37-ylP_?C2wEF?JQ*<@;MQy~$*vpu0`PdDfy3Zo2q~AH>?!M0%6n;Ld*&wbO0h$V{%G0a`<%&EKi+igBGVo znk02aRBZ8su@KVuQ6Q}ej)+B(kdeTt(Wq?bDPvv(-U@rDC9Jfk$pt=PKFkWX3n<@Z zEoGvjNLMN$JegmeJuv7lyW!$1yOht!##sH30C1B3(~FhaOxRDlu} z>uTG8C`fD~hNRT60qFuRO;0)*!q6U1h2WHVgxK6)o2{B?Ul>-S5@e_rx^k5>ErNrR ztURxsZAx8{C#%_PQ6LB%X<7_M-J>6fkh@}HqziY=okp>1n-bl#T6;iJOcFq@Zf!tZ z6`Sw+Hrs>R=;0SK&R!oa*k%0u;wG7P{sKNKzyWSfU!haIH#I6*|yWy)nYb)}CMPP;I9C zkMCF-fbH`PUd7sX-+4j?%*v^`SO`4cG1_!9vjWpFGtm)~KzFRgDI+ z0LiF8Hnu++#`f*l;Q-34Ff^@5H_(&S;!=D;Zzd09d*~bksW5Q_QT!f75^NLICJTMI z=TWehDI$$)auc#gdSU2j!P>4PCKk*I0BMe*Xmk^gVee>IB6&h(pPCVe99utZ$OLhEj7V-Pct6@m2Y5rt^M=l&zi8->U` z?U)5Xg+It_P@@c|J_yw+{A7XF#+EEMB$v)$0HpA`uqugYBGGAfGy$tLB~5_kHt(9q*@JsEtf{&uey>tMi1%hz_HQ};k{0+vjt3% z{MwjaGY23%Yy=F##W3PGN7!&HlMTZgg8lF!y32>R9vd@Rmh@(|6IRFon*bj+O~|K! zum-qkwGPQKU4$9zqOtO2%VOOWHoz6?U(-zw;DDmPMiUbFwl1!?T(f5GBmo9o5K?a0 zG61a(!lvWq*f>VqbXozHOwO=qW3L+83pX3i$sqB(m#b9^@ljLr+Xd zwb1H@!y{y&!61YtphfH0Ol^ff7{qD_nw{$_zU+g}&FwE$Up3^wpXs=#ql|i^bZ}zf z#urzI3!|qMBPr4zivNDz`PMpqZnBW-b#wGA5IN#b9eNWC0?wdnvk zWD=O&DAmas}Sb|3ZUR= zgl?5c@jiJ|)kBCGJ|w!$$b-mumP2TeM~EjV2%=I~?6iWIbcPQ6rLPUNo85C?r9}Ky zEW%c!c8rNg#SA3NBlb7w2P?gT0CBLWMbzF0|KS<{8g_ArPRo=jBF+`=Mb!nFp~6Na z71tUyZ3bYMr~vRm=L1NZ;*`PYIB4#}I<>O^l-;KjtUiNV_)r7-le;KYB#g)-)1sX} zhQI+smguQlRG?vIzMZ9j8kEXu5-^dmqT&)80Y!$p!gN5B|8T3rXTt)ev{cR;GnZ~5 zdaLp-WxCOi+Wczj%n*efvA_*-Qy|e@BNu5&>V%NY%#*_p%$(&8)0awUwR^}09fZLj zH?ll2iO#A#WL0;fQQSwk-?74K@TKeFuWss~3t};{z)Y1WZC(Q}5RZyJm^eaH{xhDc z0@CuT2qvqf3W}5&0Zz#piGV3|z%#_p_8)F=5sQZ%-d#s#pZjpbBZjdJu@I?5z&KDz ztp2*2cmc2)lCIvo1Jb3z{fG4}VJW)!@CXW5T@zbJ>9~s~R>(>{j5ANL?eIY;M?c1~jef#!{i%lkwb|OsuX(KllkoM~+ zxyfltionP;my52gAjqC$6O3%$lT9Wbl~;^w4n@jpC369@$i9jyacAGdWM}8L_nTkp;6qeYuqF-X4javg%Gr#+WZbSHeoBf zYxHP2TJ_JwNvt9`#d9o$2pJuyT2->reRr~2!@6?uD&kRXB=;qsWYEZipiYQC7VK$R zgpeG$x*-?<`>BO1FJj-9z5{Y|D==Dw1nW(?Y4Xvg=l}p;h{Frqy35&l!k)amrebHZ zedOEes(B?!j>_@is?Jqmh}IU!C4hs#Q27=@7F4S*yI-|97Mp;e3`|Kf|Jt^Sc|#+O z%|0M-A@zi$kq)y5k)$$-Xa){th%$L_U@2K4$aEW878$0MAi99OR!r=NU%Ev6&V@Ca zm~fI?!V-VA=}91DCX^#kd}5?SQ9aPskTnCYzHzF9+9OKzU2xD z6e~H#7(kiYBMhL*PCC{p0Tyk?l2m7`3#yQTX^S8S$h6cF57K|**dC8~b*-W@EdX)eXzOepOaKMD_`#&8jRv$LSXzkG@h?U2_#Ltj zv^-{^STB!Y-Pq7TiOu?4lC`c|gcAiPrXi)tqU+6LkkXch=O;1$ zx1d9%BoN|@f)gSDG9$<}eW7;<+>wURCn6PO7@hJv!9q(mps+qfIhTl&X_|b))sg)P zd}wc^!xU?2qxQz&Sp5vcQ=`BaO1rC-0rp>`#+eZ?r_e5{ zLtKNm3V47)q=M~1b_g+~%un0i?{;GgXPOXClQ2>sSYL%fhE`MTPh%1_5FFGL8BSBt zE87o5OG3PcG_oco%ix@1$fWDqFku-1Fi-#5Q!d)#qU;g$IlW_#V|}V$Z4I$f(z;63 z$OO^_%-JTw&g!Iq)JoiGk+3Stt7Gd$>QZdQO>P<0acm^t%vMqKNdqcVZ8*Rw(!f9* z55G|p1UnpQft_u9%O$=F`!$OeSqYip0GE(88c~bEs|MDF<6`SiAgLSj6;1OvM2P?% z8(Dx-nLCp)ZWq@HElMT;U)srXLN4(~c8lQb*wwld@O0HA2+py)XB%16T@4b05CJP# z#$pnDg|o^rzhr*7pU^!Q^;6AcDgx7H2V)P6BM+p&xB>1UFQ9;qSBgh$3H@qnz(5~} zLE8+E>W7B7zz0@7V%jt*7r25T;EHIPnUgCxc*vFmo1%W7EjH`qgdI!E5hixi?zR0#?T&I&( zM0v)ib`UTpLU6?{lP97plYE+f6TX8Ot#_W03TRk0IlXK15Z6Qub+b^hjJeHkQJw&6 zCZ#aW5eHnX;u=H87Gu@SY#$I2UkUAstoyRCfR&;P5>qP9#OCG?5bC^x~Ci5ib$A@PGN(j-o>anvO`ol8!6=%$NJT|khY2Y`#EAz3@@3Gs?1jl&gUkwv46X7OsUWd&OxKqp%Bm{#bGXQLl0rjmBza{CVi9>4qX?)fUI&r=RH8jjzj zeP#Xr;@+}NBJD3r-wR_%8P42e_7Z9Qk?2Ly75?gkJ8hJ99|UuBjlXrjH$LgX%w(z)%%nkE z+PwVqHc76MmtsFCCNfsf^`j#XH=@HY6dl<=8tz7!Y8vhS(rV0el01>ZPqQ^5?km|G z5vH?10Pr^Th6sSpsEXmJ1LZ21zLaWnXtabS87+mN;X9r5gPfErje6Ru$$tZpR5!xB zBl&D{fusyc0}7*7>Lj-2hZ*16Z!T9ENumAQilVUHX{&==guO*YK2pm0QHU1G@{BU9 z7EdF~Zleh;5fhk&%FoiyMN&!i6D}mcD4HfhNs%4NUu<#c4!OtyADrQaf2+~3+ee(! zLl1}>*1>iz@<#5rmQ`*ZS21llvHSXj_5H8+K71j<8uiBeNA_NWcI^eY)WidCV(F9Td40Drjb`}ho3rHB!fdgoNuX=Dzk1~_jje(9 z;%XVTdjE*-xzQ-z7R-E0z`*JR$>eEnhFKf=30|%nFl?aW)36e*^BKdyJMFkrb;AG@$fY!Vx=) z9z<`dG}ME}97t*Ty+oOWPgsr+Dbf&xFsi}_cBq?hqqEJ`i>B|XR;1zD88dDur~rTI zOh4_|ZE65C32 zsqkGA0x}(7sCPJc#P_YL5+2Jq4ueDS>@_zPrBrn+i5`;(;hGKs7cUzebU}yHi2yQx zAcyip|DbkGn4cAX_`O;`clq-ejE9_@d@@o1AwwBT&mSgoSx<} zct&O0TUdm7MZ{3goItEIQlSU`T@*xa*e+UC4ql~+BWqASRxg!Jd1|i54Sh9~lc!cl zQqoZgwsId65syL4YRHEwXky>-F*?nP>r2O7VT)i4*qM9;vs8Q3VqU6ZfsiDE+*eE- z6{*`L2&yK1Bz8SDBs)7HE1zLW!YXs>vfrHyfa>C1DIpGwLQSIS+cw@hWM zXFL7Qipe;<2;u`*60!(x`@YF{cJ3=dqDniv!!L#L+;?lW0e(1cK&7e3OT8)w;Y~Jy zNRrOQRsfoUGKC~;=NlHV;-zQ{(i5_W-7j8~!={#F+CetZ2VzzB5jH<$2{&3jlwwoi z*UTbSvYj9=^qcM>o!voq?Dvs6!0UD2sUabW1jnO=oR6Vw zqDo5$q%k0GA+mGOnJ3q9UEowf6b+|vw(7CM4^2<0VLfX{tpIhwlLcX<%Eu;Mz+z>z zx*v3c&*S&sprgd-iXT}Tu0yZ`rX#$k(jUnniZ=asmPL}oz$xDM;G~^W6f94{bOI%+ z%<$l(V;nM(jJ6SL%N*^Lbi>e6jScF!{0F?9NB4i-`a+uUU^0&0r}@?{d~vRI(@62G z5+-buwaR6gKUmhyHmu1uogGXj5|{%863d-q>5#g+W8d4&0s4t8Nn2t*>fiA-nTbBz*_vzD7x0fBJ^KC& zkxBHfcd+y}A%E$MlS-IMide{9Rgs3O5&+mpFlyd7HAzYpw?W})L>|)G#mrQXMRZNs zFkZ=Jt*brgLm5c_;fj!4nSg4+IxU$wvgMI6`nkiS8@^}d2NjF6zcv^*7bbH__pZAS z2O<=SP3GKex=B^~h!^7a+<~kh4sBm#Ol9~LKqNeEAJt9m2+@?=McsHi;A!qa-AE5FfU;LTM5ZVtPr^!W=IJ0qr}A(rk0w z1TrnM>UEN%9sOqac@2Y}M}R5wWX~u>HiUloMSDP94m9FB z0^~WM$((VWCO~ro5CxUYk!B&1-`*rs+|jX%=fS2@eSuKxK^4fD()4Yq{0(4}FBF

v$o6;3o8FTj7OZQ$+&1v_0U?)0$t_X9pX?4+RPV8pJPwTbkTzi{xer zTTgC(25y)RLW4WR&mGw4A*WqXF;!k)nmvhr9bPWY;`ao;zqkAI;(G$0uC=dv%it$F zOW+`yx!3q6;ckEFi%Y~Xm6TA#-N(jmwvI_xHgqyLG=g7EvXoGQ-GWMSvs4|ZhRuO& zDYEfa!A{&@3s(%^PlYj6tTJ#}WiKS28~zWy*`xShR$=CTxPAzaXhh5i%XFCFr3eI% zk*A2x=$#7XK@o?d-N5yC-DyXhdJ41ta3G_QmdFAf1SQ8pp$ZH{##G5PL*lBr@7Sie zW9mbPV464KzUsE38uqw+QF^p%JgBDbyB?Rn zWC99q+QGsXOu*k~b()x)fbH*f6L7uO-2@2pUu*dD>j(GA`U$UVN?Kq51*21W|72^r_*WjK4;<|Ro6my$SM&!E@9FidZuC#8NwVYv=OLe525v z9DD`-HG!q>+^q{|9E#Ch`n%HeRGSK>b1+1Wp*=*|kye*5|NbC(yQ`LX`{<)Fsf z=Tq;s-`?9fy8PKsru}&5VcHSUD-c({)!yR4pXgY{W<7PPq9%}HJnJ)>w?n6D*lkC|IfTRXT#bbw}bx zTL+X2x9>CBsXmX>p3%0L?k12%I8>AsS_raTe1{LI;4zx}bW@ zfN3uw<`5m~DDcYwglZdrA$C9cE*pYL@$!^`(1ZgmyIm>HHnXs?8Ayk_5^id5u?oUZ zSo}4Gp9E{5Ks*ceEu@)W$A)PCL!HRd0BqWy!IGGn_DfsaQ9M6RP%!8+J&1(A?id@~ zG!4yMD0c^D^dzd`L$O|!ySdtWt8il;HXQS$aMUdfL!Op&~MjC_<8L(K$fM@hwz8iGKHxUB$ z3D5wJEjT1WgVjaEBM?@bdQj$P=Ot>I;n($z_w4h%waIxKz)7srY-x=Wp3>}?_X=hw z&!_LQ1uk*sg1@A*ChSsw(3{Tv#rGR;j@`x4@X$_m^*4_1?R@8MOb!l-#*V`iJM&*} z+Ku?&RsV#YL8~EmC;g)X9k0^@L&1o-8=%97e^%U(6L+@|j{Ko6PX%`*z zhNCdaR`ip*=;D3;vI33%az6@ffBWsgEokY@g8mtM?V|PX-+Ak=+v|4yb$?0X-n!SD z5&SiKD}UCum7l++0!M#s7NGiw7?!&>>4$c2Pwo(GqEGMM_{Yu1v&#y>`-_VF zTU+<`CV$o5U!|rYRqU@TV{WYvclZ3Io4p4OcggZ#{;Iuq-a2sEF@ISZLTmi?t-qq} zjdo=g^``xSzxw;6>S#P1_2#eZ#5>n|_#yJw25+7^2+ZcaslV2Lc<2y}of*1pMGiA& zdislId25>Xt{Q*QUe#k4d8MYm_NHCluz~Se!yvQP&YoR6iQv0{kp0J#$9DC@@X$Xz zeEZwI?Afioqj6sw)ic9fls^?~&)27Xy)}*IN7Hd;oSWy*;zqi2I^4^BH7-qZy+V`^ zkBp;}%>C(fGREt9cFZCz8(R%jL zlY7s%?!S8cWc$^FC(j?>%NFKme%#)R=;hh4^d@>gTMxtM@~8gplh?mT{kh%E_3~$h zVQCu8CZpqMeOic0(YwRRbUs@ja(%eF?!*|UR+}jKLKam&h_SR?6<@s2y28)?MCO%x zN(wXMk<(Td@%;e-b@mk=yN}KCPFbFTJ0i#5qa3!)4R`Isf%{a!TeWSs+=ci)mYeNr z#pY=@HxyjMj&t2xRRGFgZ&%=H1=#JJF?7F-7L>a+R%C(51ZE8t2jn+NTZAe3hJFq< zltn|7#0tH*30UWTj8L_A9Xoz!zI#Q$YQg9}J;Pw1LW6~IX%~*j9`>fQXnUwvU7aV} zjkCC&gnVy)QNyjI;heti>`zv8_j;Z*8y_9Kj;0T+S5BW;)%;zm`FyfHm|)_McOMK# z7qov*`&*I-!}W14`@>0Nn#~uc`hHk%p74FLJ}!-O(|lpJp5tm~xBU}W`S#2Aziwyq z`9j|s%<_dJYjCgG^bKbFHy_gUblf|Ly4gF2hgnuKvSBuNZ*pgM-LZIXRO;n(M`>7U zM$!6wFr1aX=KaFGd31lotHs9i!rWbbHH$`jrC0rrAEO|}=DFeb$Gga~8q zrQ@S0Yk(T8?*`#hIMiyks^33nH3#db=z)3EJ)Kdm{kk{po=y&wX3(JY()`0=Z+ZeDb=a59{OzWJT;5F%ne-LEQVh27|Q*aw`u(d^B9f*BCBcQ@`Q zTv7j7y_tE2%1UnQm)$zRL^?Xio)r#`oLL3Twx4|W9m4wA!+ZDd-g%l5qxn-5l3N$x z(X!URTE2o*4o#Nlz7Cv|yRL)Vn(^#BSU`=(bYFu1a5_1Z zh@0Jk5RQ>K^Y@2Q_wHmeih5& r@cG&h0aFtafl_TTtc54<%PH)ZkE7SVGs@X2Xp)Gr>9_QqJYppk5n$lp`(L( zyUa1B3QMTchP@=kHfa}SeYvVDMXnUvo3yurJc3lJ>E?2#eQYUHJ#9~BxI~6QmB~6U zX5so@9fz}w*oQmIB4%Dt(s)rdql z*&cRwmVe2=3${bH7DesmZXJ>kE9LXI-kmccaFn8Vi4pOB{WP}L;p3RIyYGT+fq=%l zz+~C&?&tEk)3d;lho#r~+>2mJ;PA=5;-h!m!wuz&Q%u>H*k%V2CdBT=Y9fE?Osv^_ zGDV{eXAp3IkjpM;6)6iOAErnm5HETV3HaoQ2zLp$cASgla{hEQ>ATR)G#X8MySe-s z5)>6{BInI?e`iVLyk9MHF#n=ui*U@P#2lOla}WXQ%t0q}ytEkijxo&;H7~fI5*-)F zlp?{Dd2cwD%=NOv1E*+mD%*`p3&1L*h0n6Z1M#4fUmfSN8J4?xf>X(qBBt(%{Pv)3O9xe{&(LrV~ImYCT_V#e3;|0uVg%asz-3lbSR!_xue=^02 z1^}+z@Zg*TR%D_W$j?J*Htho%ckyQSHYV(Tw1d>Gu2t4f*4pK@0e>7fErKMqTnB~N zo}Y~-2-_GIXN7YYv<`3PyM4036_`)D*)?+nXptU4P|6lwIHde-oJsvdI0LfEL2l?B zM>eH6Jc;9TGn;OYOJPpM#fx!6g&9Gb*lcKsFe_Lu!LL`4V#rbNeK-3W_Ib0QAI%tn zC51hk{rSnlv&M^glUVY2(*N^Z;{9YB5l2^bcKfje+de139vkN*BJBS9c92ztXEIl6 zwfB3F^^Vyv&+6HRXKB(j5%{=mmDgovEZGSO+ts9-m2YjQB`}g)5bo{|Oev|5W zBNxd`Bvw^kUtjM{_bo&`D~+P@{(O)R(Jf@Md2ZuEZ+(tWbo&0RczVG9yJwlx!5L;0 z|If~{x3UupIc4eW12UJHAzQjw9k2{vpH>V z+{i`i78!Ur*6%!$+5Gi|=PH`1WX3b=Gne<1)zkmDUWsbRg>?nm?%_(R7w?>(zVD9Z zLq1?JzY?&_A>7@SM@XnaE`PI9*mW1|$$Vkper-;UrZZX(ee2;EouUgfci~xth}+eL zUU>XH(m6=c9zi!~upi~tPIK=+9(>&WIQTgHIQ!Vk-#lB}Po%VALMR)r4`0k*`scGf z0ds!)MfP9+!~c$M`hWlL|5kthpa0Ij|9k%a%YXcjcIAK4_ka6;W?#M-zwE+w4u{{C zZ`>GvQ{iuJyq+y*Z;pY_$B(#yset8{BZElb`^TG+!*v>n;5{d(l*W^jT)sHYuhBAI z;WxGN?d-q&^Z(3$*>3L}w)d8AKf;hJ^`qe^*IR3r;q`y{=YRMA{g40azx@0EUQO6N zywpYysn!4WKm6-|_)or7g+s_`maY8D|Mq{_rTJ|~upScuZ#T35`oH`$D-(Jh?zjT9 z+!c>MUHVV{(xZSwn^rc7+&+R}Jfp4sQ%+Xw>~{B~k{$@akMn5M&Bx?w?Da6X7LU+3 z4^0*Zo!uLCzbeOm1~lTm2S>ND?|}R&%!hNC^X7t_zkODiMi@V7=TuDVNM&9!PX+{y zOG;c62t$>uKY~y%0u^O?H*QRwM0Qw|?1B1Cu32}i*$5si1&@5Z8WbN$piYv5o3M$_o+(QvBx zP?<@@rkXU@kLKP5R3uo<2*bB=`-p7ee@vsjE_{dJi_na(UK3Z~a0o1{ZgxDeAPZVs zUSfAqEi#h`>+7s=Z(-$|2{$|Ztc<{UzR8);PVBCTAVX}@;@c{8_v*Fm)^nHR6}mp= zlRRO#JpP?MgSPeltHN~EMN>PD)#Y#9JBNfVC9L8&-P1tZ3XWj&Ir5IDh*7L7-8%)M zdwQ~aFW?Mh4BrjM1P9DWHyixa2i{_w1V+m^<>f4B3jmfdmwa?cc%2+^Qt<9M(|K?B z?(Wh4!}0LRGsJCz{?zsKGf6-+L_og=`?J#Q=(TwF7CJD+R0CqZqv#RA--v*~adc~5 zTE3JdTzD>fFnLX+Gy9cvlUpfr*PZ9jmAqmjTrNXJ5Dl5Vx`T zRyc0*h>9s!M7TPKckBl1I`oA#uHOX0qXl%9LW3JO=qHUTOoS!G=vnKuH#+IPpXsiq zh!+9xnV(ib=k9g0o)u$1%Uph(pcFd8{6qzcAj)B3ei&GDT=-Mx(8LPLkBesLX+%vT z(RosNbZ#?K3#UHqSuQUiF^p=>tOaA|Y4s|~Ejuk-9EJ7)ND0Cb6^6n~lY1ff&=upFh>zo_t4Vx;pW+dh zW^xITR4!zz5)&Xug7n|)({j8^ z2yHZ(`fNcANEms1ba%gih<-P}q{%k7iN9LLp?F1Gm#?uWsGA{?OMs4y2(OSp9oP(! zzxH_^;R)~)oefM@h}Fm~-NVQvX0#+R#h1cx-p7S5qWxdb(f(2>`|IRL)_5*V{eSEyTHyHMSJt^f;;5w)@Sx;LfHU77O|qiCxa*&-HS%^ z-p7yi@;?@3!1Ci);wT13Zzo#^8zGuoa#uxk)OI*>+hT0yocy>sU#rW2KaRF1+s?^K zn`3SQmyJOI;bd=*{N~R}8eMlnic(qO1HmMfNV=)cd;4;ZF@05@p^z3Pe=tE6Cdm!g zdoRi_x!ZdYt`{pvhM^)(`Silp%eSJ@EXvTs^!&}x(k5M;TT_Gf1d~@4Uk{}K6Z1JX z3P1-VK~XcNFkx(JL-=x&FGuVB($_IK1nHaU3pUivI@KZ6dn`07)^8ns8)jtB&2OiF zt{)ZW-O)GcOJ=+$SX>_|({NV!*-{PKs|InVvzu=dzDf(V6$Y)BV%SHCXj5{1Nu)Vz zaFO7s!m!k*PeZurC6W8sXbj@Oa<_WD%yIOD(2EgyLjEa`6F`ZMA(MM9=Sv(_`-zrs(d`&DJMjQLsFuuDb6s@{7#JY^wWvBMUXDX`oFE* zxZ%QfgfQZpFDfr@r++93gmg{fio^mY)B8PAp6QVgi;)@eH*UDkl9Az!8$B0;bWVKQ z+aAMoX6P2I*o{E5oDA8WA$jXMlDefR$9uX?+6>p{J|YpXo8d#7(DAKdaHZB+YEFxw zxMxgKHTNB<3ThMeG0f-X_Y`F9d90;LQXup(y_m5a7M1|-ED%rR(C#{Z*H{Hpy>$oW zTl4ArQ(%`^ZZD_16LjJR>^nueJt+BB^SxtGqA3PZ>5PAVw88SIFJ_tS$U zhzYiHtn{g-RuQBixDCrEgz6yZ7Y}NNt57qgesjJWHRE-ZKVV-#jklWo z&%z5HptoLA6Z!^>#YE5(5e%1zfJ~7if=NsS;oBk+^gIy^>Cysldju2)&r-T5Egup| z9RJ^VJAqu7Gd?@&vf?tf@c2Oo(#DN*>SP*4!uB7a*N?C31nx z4E(4`K%yvstcp~}sl=U0B}{cvPj}@)EA&1ZVxv5TC@rnMH;+A;*razp1up`DSBVnZ z1HTl4 z9D=pYY7d71zxCJm2fr`52ESd~H9$Qscm*NgLBA`4*>jk|D$!FOfQtru$AE;T0>UXz z!nw^0PDIj65*KF@ir=RBG+9GJTujSR!D4Jwghu*-U^aa#leqVA%yt8XT`w5fg+^WM zP~kym_ThBg_5l(04aUxmGN2kFgni#0MN`Fq?UQLb4Z(%*m5>O2K-Oww&akb5JA|n^ zi;hy~ufu3gQDE>U`MO#6pOvgQSJ3An!ZkZTfsS1>D#| zam{S3qb{8|t};BO40CVaO7hHQTm=<$;Y)-g0U|VSs%q_seRHQy`{14`O=?zec1CIh zqUoJH#y}#nRdg53iU9DQ`wHybLc1!GNgL+|X2~%w5LgNy@|>+)*gQlPh7df+QZ8(c zqe^KG?WYg`#709Vw*n>!?JMHHtlwdoloUx}Q%ucG)qsiJB<928)PMn>6lfOuh#iPj zzjn~6_uQkj`|PB{m~Ioa8u)H;J8P;iaIv4)a46hb^tgf!IFB$Mbz(c zKwH1Qm!STabEx+?O;R^ewEjzs`gydz5JxGDqd*K>z4xrj(E`5gcupCKD~#;kFZg^; z_pwS!L^IteDg-L)evb8ezDFN{kR53B?%B&{^1kb>qfho~qe4p3oH72n2+e zH|Z##h@2?AjzE!0L&gi`+>}mGVZ0*Hgs9erF=uJHADb3loT4@_3>nQHSwTroRgnv` zbj8y5Y@-kfEMIp*wc;OI3Z)VnJyf?3{cx+;NxAUV7V3$D^2Hj}g;m1*3rkCPg!}td zOb#yTy})N-aN->ci&$J~bUUmy*}I4C_@g*v;aD1I%S0IY^iO)q7YZU6y5!r(TL~`` zL1_V|=Nu)>|&| zB8w@+MZ|GX`fr{b%>{z=^lg-L&gJzOil9+sqFJW^Es5rFv|2W=NG<#^{{ei&nNf!j zGi)7VkcKIUB=uaF3=8t(fS4?|26i1Vn&6WLK=dYhdytfvVml?x>1&uiNBoo zc+$ob53X>Oq)W&E^SZ<3P?@ zR~P;REbRq5!t_;lrJ*4>jQ3Ah~l|Qo-LqLcBZ+m1b+~0tm*7o6dQDw@&+m zBiNQs z9s0_hx^TeVXwW+z;)kCDDBA**EjL4H)}31NHARlr^U}cQD9{ajDcbNBDL!F8&uEl; zks_CJvkJLzECN*NK;MXZYyx??3N}x_`<%I%UcR1_c2h-)##o&n_2l%Wiy^y@Yu4a>23bn6#ewc^X>ajpCvS9 zrLy2Seu};4_{y$_b@m7PeAD9I=kI*EsEw3zhf;;NdQ#ia{(!t z@}OvTt4DUodk8a%-F6QUWck~v@}*2A(AT6i$a61L4;d&^=&EHCmt+=L> zuwS`A3@0=Ah>T4|m1m1_TBaMUEa%l*yJWgl-12XZ4Gl7ZhjBh{;m3NEx+gU0QD;*O-1S|q zAKLZfdv8?+ap0~WlA-98+&LRLc<~?t>D@+Dqu}{~s2;JgX+Jt7t2ZO~G2`eiWC6UI zf?x~|0rD>#-f=EL6vrP7)b<(dK6qLOqqA6}q-sl{ReO-{Q+MG~Jn(R+I0hj@s z;S`NyIt%N_yk2VH^6I&THt$xq*{2^7-uoyixKF?mMo=2llM{r-hK~8{XHNehn#H!+ z(SYf8b!5llJv%?K#A{TzcSaAl!@l)w;M6GZ_Oj2|%$~ZKIuL4`J!S>smylGLz&H@Y_cWsRnt6m@+cr|zHR(^(g zuY|6JS_!5rF_|aSLY-0>&1MHxxvT5d!d{d+RRQqxr(50kk<#BsQ+B$edfy&9c2(yZ8xSPyzA~W`u22uHt1Wn=A9TYy#C}0=?JMqeFrr zZbr&U&IkkecD1gWbLh%$HhDtfR=D*{RrrJquY&Hg7$qsl?OchJofJ}bu7Q-o^z)+y zcwU4SX)7eiEWykCV!UwrkjG180Voc<7`wWe;b=I2Z(F{;Jff(cH{OZi_~uF^y-6YI z&6P-sJN|5Z126n31d(@*v|}N~J4*O|c^rI*nI#6+#+6vuNMT{)N-U(f@U!9JYWa10 zG{k~hkEJ*T$2Sgo?_TNXyL^!MDbYsIYXLpOzYBV{V)Ue-_~=RmJxU?y(KQhCca~*d z#oRUvd=W(+YYB!{p$+T@jkJt5f~;STt7NA40oUGsYt|KQf``_EckVrWyy{>l8z(e#-JW-i7MHWs`qhJn zTR2qbW@1#~mc$c;3oX?`-e7~E| z_O7TRz|lMYk;`$)_Uv-@WjKm<75NOl1o^N(d-`BeOvW^bS16gRHTwt(j)z480)@Yz z0Ks2d6o};3RKs=83^hlcf0Zx;Apbl;UQ4DdP+}}lFt#VFqzLqRrLahdXqEspCL&k* zyx@_hqzeT^lfObkeNRJ;&nSY7e4HLh1>oFLFSVXr6P*8`L;gC7fi?TCg60sygXU1d zpMV~PaMqSn##wE8FO&iF(A{^s(wDpIq)k&LZC~>nK~VOgr)7ZMaIgfJwVBPX_!`qgTr5;oWeRN|#D{CWUex zE~`KveVv-@^qN-1)zol@vvO`vUW6a)zT#NyuFl3@fJO)<1_8p^8~)O={Gjh}Cq`7o zQ*)*DXUO?l`t%uR969?h5rYcPE}lu65`y0DqC!Eb@xmR8Z+>6@a7cV})5SOM5Ny1c zSf%OWNZF*R!jo0!f$ltf_Hg_Dy;nOA@Bf_0P#-N%_jO^2IN9-HMe}DC%3FBS%5L4J zv=Uj|;r>`Br*K|`ON^v9g>!(_cv4gjh4YjV@j6s=`lPacT+6Z#vY0RDW`p!X}PK&TmyU-i*a;qz@7N&$^^$QrvRpN$=w8|Pm{Kqd z4QYP-6z-OX|IZ6~OE`Ah1Nw#j%`d^P=9DvP-L=xPzq6E1yqMgnOK5w(7c< z9(1@)mZU9)&Oi-TvW{t7mB(h4*5$dib2XW##wLxsxRcrTaxO?PG+GR z@)Jkb@y!GP?%pRv@%hm&Sl*w+^eSz8HOAenQp^4#l2*k1EEv``PLJ{s_QUvmJIh*_BqNs21OEXVWX{sle23lN! zg)|Dm`hb}~A4gk^fm~hWRZDh*c;)uER(vxyYPM z**loo<8&r=jh(NwU@x~z3rq=xShyH`EY)6IR0U!KuUVSm(sdIcnfgtrBvL7)*8Wv? z$WRG2Pwu$ig?%6~f91-N!prIGy+3Iu-}yhAwL>r#=(=N zMI#B56uyw%?`vks-hI{W{u@(-roDX}W6b&q-8Lv+6QMjVao~vYfkOWdxuBkMg z-n8TnxH%GGP)e$ktza=Fdb&yt7D5azeh(3aQN9qAdNzA?f%QZ*fY-@cicG()s!lN) z4pEvb6L?B()UZE_e&onR?KM)s=3H)Y=J((c?Rh&M!b@78=~y zxwF0SekRw817v9Q^vTx!^CKBZLz9)6({S_7^X<)7n@^r?pMzAuCM{F00WW_Tj_@1nT?{cyZDNulS@+5@WpL(Xva zwpf;e?tp-0NRkvaHAWiHAUXW_k%{j})^LiQYBMu?oHrir7BbY~sd&#eAY|BUJRFzM z0fft4ecp{5@mCU#udG_{cF1pua(OR8*m*+`$P53pB4G;{hB^Dti9h zqUWP$kJ(^S_}WF!pL1kSAk@sSaYaw8kRD%YC_QEor*3+=$5$FksZyaYVAc88j>kZqjG=dEVac!xC2_nHVhAyO`I5NbV+^GL`Q4Q``Ywf|@2-KP zzjMu%VQJa8OTj)a86C6b&l_m=`e!OfgFg8?)s4Q55fqpr^YfMH`8kE2pRa+Qxa@n^#ik|}WvR*1OUfiqGSi-|B>fr-CQ zh41&vnE2^RO#GC>#8212g!jvna|45+`Im8{v+sOzzLq+maQdS5^0xkT^;T4?ET}DS zX}A)7syaweH>9xCRkF-d1;IFn!R=pg`QWPro3*6KVcEfUF1S}>l{$(!pEO>bw zZG{9~<6M`N36kDSWQxlN*@B#<-cZL`@!qZT(Jo}#QfzC1^*+VEB8=6=?JC17Q8G-S zgv|$+RwJi&kbO3UTqP4zn~AX6-2oi0RBuguNvGB%(vW0-pEtFp48}wre#y;V)AO7% zxe_gt6j~-%q9x@8d^W^fCE6A_Wrb}K@4Wl_GK=)aY`$uz=G8&c)DDRLJl>A&>(~{l zu|3(zjs`-Sy=i~&lbwNQ!P0qeWbHQWa30QzaOXt-h@!_(@Y=m=uTtgZY?u!I4M6&C zRBp#RheYp`ZN-}&*CdR%HGK-&4H zuCm#dbw#;0r-|;~o?FE>=c1;bBh)lwqkpPGSJUvqAKC34Jl@Vtsv+9olrFZWP*WP!2*dVgH?y80B&rQ5B3LA|UKy?{Nme0KlN(~ZqnKRv(y z^w%YVkUERWJ+wDc^!1y|cmZ%$21)=p9b>*@Cp0IWyKv+cM!t{!7W__`Pi72WSkFGT zkmJnu$e{9xVoxuo{y?XMcfBRjC}2U&3NI$?mx?2?e0A|@7gA~{B$`k)G3tv(*oVX@ zCS~J;Ss#le=nkjj<$IHt7QFPfe)DQuKR_{r2HjB%FX!XtZ+m zF!-O>XiHV<3#o{>OnqYuiZ=Q7ERZQigaB{EY+{W_y*tO0vhak&ZChKHBi9_Zu3^B1 zB_;4o$(T!^NiuaFJ&sQ9xWwNdf~fX5NdU$h01EvujXw`rPXd-~@oyBrWD8lKe%p9t z5jxv)6k>FNCF%v@npf^I0y7V!IRauNpp?i>6lp-n=iHBR&!SkG!=FdSCq;u#xhczr zgJ}Es;;;jeu5qj?FBUhrkKyQ)F^9jVZ4AA)FfEIeE(tn_a-oR=nfmPBBoXqV$l{2A5YXsbQqSN1oVzBU+M7wXIovr${C}aE z9K-czB#FQJdf?Osz-GC}!OF}%PIF=DQ}6E>w2{~A_5)lO#ifGk;Pv6fG7V@~)} zdtcpI@+Lso;P@XysW3862wU*Sw>Q0-zl);eWUZsZmiG5e8r#G3kLj2Wtw;&ZR z8saEafSa^n3#7BBE|V5>VCNcU2x0TmZ zSLGTZ;y+DZ+mrqMQ6#N;Cywa+6*>zO`P5=R2>V#WDocF1Vs)`Tyal(pZ%Lb`#Pw(6 z-2}L^2TQx}{yuW~I*j`VBOzFr-W8f)V+0+%;DZM4O^LGDyq{iT-hWPO(xK+*aDR}h zDEa#!<-9-*#Lg=T&E++Zm-^4ayzmw8ThcLp@+_AHXY3`KIBgV2iSv>uAFsgk42IE0vIIR4~F4q9w!EH@1;&I($< z#qD(W{CU>Py@dm;(|fa4_o+CEz3Cy{l#{QMD)cL!OSNPduT{aWT;vhj%;{LlC|wck z#qC@Je|+l2%~b4i#_Qjb3f0wZihO;>!Co*v=yO7p`Qs5a(r1 z-iBJ;w*e_MVHd*U$<9&M*4LMM9R=n;n4V_4@X<%EoMI}`wOV7{u)+QX0i+B$QX;VeFH{357 zto>^RQrVY~Lr&UDUo5`{Z{gJa#S&Wj?Q#&P-WNYqq3qa7VwN{740s<5s}EonZefjG@E?lq1*SFKxJMrc3(wCd@#2e^j^9b9p)XNa?x6H?PjS$1@z>>@LjY^o<_%RjC!Pr*8Wy1-~9Sx?r)_R zQ-Jdqbfg`eyX;V_5@+cFBPM zRJ{GS-J5Is3x(*h9Tm?jcY8f|`>Vgb&gcHNd&>E}H^0vF43*0w=1Ej?um4zj<*BzK zM8imUA{P0AvYEF7v5Ej~3-WEaIGkJ0=@ak*kLabI><{XeX$CKPiQOcBiF!M8#Q+RQ2WOQ-_D5Jk9Any<&qAL3TR@#D3&?FGRkZ%*f8gPXJJG$&S5@C;_ z^t<>{HfhZd#SVZ|d4-hel^d|55nKG1gIdZ{^ffWf3W!UZ@(QJU;Zp-${}5o3DoaKdd-zQ8BIZs zOfLJd_h8ON1<}Vj>br^783=hzf;OPpJMp4-{fM{Iv8wci;?WF0BU{jmr0!1Mb+hG6 zIa8^&^}lwjalSckL;8nroV?DwI~a|rq8!ZUha8-Ja&l5Ssg)+v{k3YjTwcTK$!2^{ z>kB<)bQo)D8sC1SGet67eAH@}s%6G&mKv?*al2G&*9WzBsZ~90lxnReuOYG@{3%~> zgXdO1@h5Ins;j!HR7#ava}$^x7dv(4w&`a5;Ss>9)JwHyd#hC~dARMAx42v@HEY%5 z|G&Mne~zQN^8UZlnQT>{kcR2*>Fycr!?OWHB0rIV*hZ-(l}e39BWv(zM$t$zGE0@g zG1y>Y65hcC%<|$*f(;1);}`q`f68h`(ogvpp3nE(?wKA*29qVOY!zjfru)9%bI;p7 zeeXGbsZ>nD_-MhqGdJg;QjC+ps|3Y}3DSDdqLrjl9uLA|xl$SDtyCEg$gc+Tg~-7(-8SFiuujUIi(mAh~(Gm}$?BI+wjM z*Ic{fr`ie(xn_OuVlJ9!%7{le?zhJGq_*WzO7FKEqihg4gaSq4*n@Ed6;Xc4_kwCM zu7;pVsZs$kf~wXvN%&g<^`O{NNckXYg{(E$0lSFnF{MG6Knx**X@hE!n)N|07*J47 zruY1?wWAQ36WBYR18rGDunsqkv~W1l5X_IBCIkqrd~5;5qoQFO$+(Rqs8cJ_nE4BhX*2-J1|HJ|1D^tDaoLNY&ZM$OIc2b3Qw7&6 zKqZ7^63wNe=aMK{pbWC!h|<;e$tDlaLfGp%U(4Elc1XBoiVGC1Wm%y}7;P^wdYeHd0H;cck!~QSU*Ww{iN_&svG1^20ehn`eMFdmb)|9U zP$|ocIs@YFReTXB z@DPFWtma?^!}bEvjcYH>r|on&nm}$Yk;Zz%saS3*x(14+$x@&waU9f3V&bC~1uMTKQweIN#`MZ+A3 zNv$7U01Yd`5gUdZMH!UMhM{LGnI8vGagCRYS-!B#kTC6Bpt{jOjF{+rWFV$q-;6Rl ze|Y~rw@8__{dJDr>ix#d_8+v}vO(lnElbUkMaeurNi|-D8W4_?=(JJjPqTrUR7xC8 zCvd28I9Zx@<&Q3ioTxaiqKQ9Q1!=>`YM^tLqj);sRC&5IPl-@UX0e3o;xcbuFgAbn z@Yg7p-S9ha*M>~(!`I*ADs|A5Dlw@04nnf$&snwc_dm8hILlb z_XXxiY9Krfg+H;!GEysGSu0Q}${$6_&|bub1*r%3BbO9avXZ6hBzj^gV!J_~RfrbB zi>lZ(D*@X>SWdD#fjAxFrS{tcsnLLN*?7+!81dqr3S@na)jSRd|Td<0K7v z$mS5xi?}9ZkF>jq;92e&<{7M3s>~7L;&7>0Eu(^>pi(6A#YR<0&$~`QUDIvWf|zX`dR&y)W+*`qMf;crqr;@dL=epACW*FZez`&!ARe>vi_5D5q~AinhyWo% zWEFioE>8jL7#WVx!J0v(vYLrhhj(qoDn}RC2O>rSG*FnB)wK3b}TMnHX52qq14XXOGtg{)Rm0-zEtEKtDwC4EY^>kR!>wgRP4 zT~{roTv69aS(^{ygKNzt#mcZ)KrBQG5Z)>Ph%2EMkO=}7Fft0O_$7O`8jUUMpKZx({p%QA_Au=vs-GN=dqSqJ5ES zL}esu60Iiaav)ZO`sSm2ppc;q`V5?T(vx;DjKZjbJpqjhUy!@@i0;IrL?iogwVoJ3 z*jAu|iV#9}tc^j?#*TgJP9jAzOWw zV4LFSTdJmorr8JvltR-81}!Aja+a<6lkNIJv0^Q9#deGbRKw6z*0{@TTOt5nVsWcN zbhnD&01Kg2OF$z2qP>7ctUmivc9wd^zyXE_;6G?!2BaVkQK{I3**cc10Rv)vQC|{3 z>YgJ|T#BXA=(Chm-J|7NTPzdAsI~-blyL|{1`zFGF`Bq>0ID)ORgKR^DFw!_Nbip0 zDw*!7GEWO=BrJpGbkytHHoq{Gf2y_+GBgI+ z#$~RweEO3?2T_suNHQPOpL?dMDnh5^gWvol;Xa$O?=hAztn9%k$dJ-E_W3gL%jA?z z%vlnAbS;jSe$#aqRKU60;;SvWVx|#O#ns}iv63W zq{Efco?ApR%S(-sk2HF}<>X?6$Vn?dkgX*2s$#J0nJQQYt0p`G(-nM-w?aDOd*x&m zITS@gWmIHo;AJfCPy#6A%CL`eZOArPby_W!EU*f*G8%3*nyl)Riu*K!nMvv-dD=gy znA5&x{8BTJq}rirl`08S^$d>=r>ihx%#xI2Ct_AXHV|xpWR@?-CN|K%*+EoG8lEiF zpeXtoGN%;R(8(oX`6KF(4rQYN>(C2P#-_pFQYqP1j_#mIYeA9%Maum(3L~Apzxo28 zXiq51?r)Z>-Z9<;e4Ir&1DFC!)%AxAVK>82G!V!V+oC~3fQHH3^tu2Jfazm-M5a}F zq*K}~$8?Ro4S)btw!8)r#;WXHA!6$yYhpZ!XoU8+fkNgjMhXLs#8qRykOCVs-Ldf% zOW{vU0oOXpv(!`m7`(Md((a0J4OY?sC-~X|GOB=26|6F9xWfhbq9GMc0u$h)C9`Mg z@@%d39oR>iXTwotOjY)H(lHVlq-DnqZIfKmP{9z}{$nr$2m*@0#J8PQxJwjj8DX~}?BNm!4jM6tx(T9k@IuNZO zx-^k8mTXXug0dhmBMkc}Smn3|a~6Y6foeFU6%p5tFg6!0hI3VU^NVJ zvB*m`RHpu>nE_vq1f;=Au}Ex<*wQ%S%a9%np#l42H9fHhYWfkj41Fcylb2G2GC&{P zsaBXFvXv~L4(+l%4%}+}4a$_mB`<9h=w~k~IvIrX09Eu#i&- z!FpwAnADJrRba;-2Rcnb{0d|FH1IB)3JBvgFlb)dnzN7MKCcr!Ct8AY#2kpp--2v5gQoG{Y?Y+^ zVsU{|F(l5_uog1QrgLXMYFQ5#Be zsJya24R?Yr=Cupt%^EawVt@|I$)ie;w8)Au`I<)U+qa>r(n8snCGU>z0~?_Tw4h3$ z93O3npHfhrhJY}|PUQ;l>4-yc5r-tG3|UUgc;l;@zARcTH<&d4=Fx89z~rcJoPXTu zi8-8Tck66)+IjRDrrvTS8g`vWC7_SRJ_@E}0OvWzW(%dqXgK;wra1W`^eRmXcQ~fV zJGf`354C@WZ^qG7)(Xr7>ybXV%7hzFiJM>%Mu+3SUO08=TGufOPBc!T1z{A|;n8`u zobWwF$CA`6UmR#2ONEYA@OpHgwScW06rwh|tZU1v*f^7EMp;p#71QCW5CsC3R%`?| zOiod1AZms$I+`+rn^GBAFcmO|pEP7w=#D zY9=;df%~Q(mczZ#BfLL35^%Ps=OhuXI==Soz zPm$QN#Fg8}W|dgE|L{*qoVP^$w=XL3!R3cJwO`E*B%=k9up za1>2DZ|;rIDS35)TKU()m>sK}DE!zR z@*G}Qnu5-Vfi&<9xC=OrVqIQbX6=8^c7p$`VJ4>clZ&H}>jBXPMIbStRWl zJm=E)>V!VUN9IIqjkSe3ho%p@2d;G0mJZK$j@kb<@zA1N$W0XPwkwaGd!?17&f-xn zlh921q@W_)3SOfP`_(iEZgQ}rx!FT*V*8qpHZ@%R6vh;C=3wVwXK|vSYYO(LE^3GF zB^FBOkUFUy^4yEdIDp@tx+b9v_u?{sQftrDXxcK|3;oV>Q$|3x-@+Kz-3*WHeWLJ_ z^wqO>V$nC-jWlbD$1HiF`DmKTxUaamhSqe%)#1> zMr}VpZjGy`&3c-6uY2>dOkkYl2;6CMvn@CYt6NQI$Ze($G4i-plTFX128$;YqS1_B2H2$)hZ?-*$8074Q8K_4w8bpl6t#PB(?du;- zcEkZQ7iQw_E`UwCl>3M^!vYU0xL78-heD7PFKf^v@)q|myUSz5sy$Tn9_h@tf0()< z#$RL|HU>j&!yNgeDK(d7aecW=!UIblt+nB1-VtV;&*b)zm{zS#*c6MO(rqrR5KO5t z>k+%fd}xk&-A)$01#vPXcD2@7@sI}I%u1KnZr4kz;a2y19{+&Ys9bz(^mT`r99a-g z3rk?V&e9qUEe-_bM0$s>@b6qhb#Y%12~4Rzzu&H)7Y^77FtWhqZJtCw~IdwAETE^{+;aR2OlGx?g}>hF5rExD1=F zYOKo=a|G8l9KZ(@Y|XlBh{=U9uyon0F);?-g&=K)uBKhzHKG95mu)%#1*BN$7CjJ0 zRY*`cD7EdFrxueda&92qF>kL&G_{U*q}DpjoNH=Hg=ZVfpegMfq!H%306`6^rQ-)5 zT_@778jO;O06JnP2?1C}0w;;?4dzYQBdK+m0P@UfW<@lU2B?)YS=n+f2qcWaf-mjp z)-bt7+&*+fYd>3EAyl_0HOJ{*4(j(b>NQcw0=SwH{5-VLU2KT$cQ#cuoRZ?t7f~oVw|MeW>EX*x zP<9YUQ{sNiIFTr+3m60?H)kd|3njF@AKp2{v^z6Bk_kFR(oOFO*MZ$ir{n`|5r^jFM3*AglxswcQavws7HN2(XsT@l_|LwsaRcI9lisrS$E-Q2sTu$} zs}L9x^0*Jmm-_+E5GfIEWA1fC0yr1g);+pdM#fI>L6%wD-Q_jd0V|+!yT(}?(dV7s zJlE02y!nQ__Shm>r?ob2Byy>$=&qZyDs#39!U8R+s1ur5SVU4uPH1(6Jt-$0Uuhce z>~vbo&BZJgMw^QK7Q)N$#;G4}i4HXB9|So9dIY-$TE?G5c)2^R`Kq$S}xILE^m220kJ?(_hX@INidAYf4y1Ra~9@6uK1MCzR zPyt=s%Y$o+WG>;RbqSpfCyx9=T6VewexIH);eI81yIHhLr!Ho?qH5~mtb#^nPjp3L z#bYC!9G%IF1zHWRF|^6N+kREAHp^I1T=u6=B4{KMDF^JAI(E6A1i6Q^t*|5pee)M( zY-Og^?9QW$xd(AP0AYK&IjM~xtMzZc=&+hQ`t=_B)z$;w9)z1@-)Rpl^FS>}Nt90Y zpo@3s7Dk9Vvx0_5#f;^zKv>(!cSNq=4?U{l4vDr+OsEVZd?6#~?qbcbv(cW{aN)lc zfCAB39;Hj7nu?Ys6hUDVT~HS=m3pM2@S$#VrpbnVO--6okx50!!s{*|hhX}LTFpah zivg~A%yz&pAu3E0t|Go+XHg>$7o{#Que4cEWZ3kI$<TfT6GjZ$gWv|w)Skt)5RK^vI}ys+QqAm!gU3NC z%o-DtE5Wl#30$UGIBKoJDleYBVO?D!2y>eAV?AdX$PpYa^de zeMCjQaesI2$b?K=uy6Q1TOY^*mG=GvKl+&viOuCc1ZHitjBEsyo3E|H^p%~q_7G+{ zXOZ05;!2uFt1$K%`PgLch@ z7k~uRA(X8j(*--?8iLp={J;p*oRy}ElJR6XMk>s^7!gdW9})2~T&v(cW}BMF-QLDf z6X>P8Z)C6W&VS1|!#8Q(@rCW}8|v)ZL&oDWOfjh6-A%%d?&!@34yL&>v(Q`y zo(uMY!1ip=jCQ1%`s*~NIf@j$bl1T)QA*ANES+?jpHRu$D=jjCqB-#~&`3RjPnjz5>>z+7d*Gl=(rbhNaG}AG4W1C|7=& zDxdOI=g14QiiNS)ewXiuW|%{dwB2v2W0}I1*Rk$P%^9le_M}$RZBtXtfyVAetrDXg z5;2%I6#KI%jM?W7R8j51VcIf}^B@Lj%$IjDU*R*tmA{}3#vJSg`mkhnS0uNjA^cmZ z`f_+gMsRv|2u3kOG-15$X!mvbCVE3Q?e@pu3JSWKff;|@mf7VGh)AmMvlW>dm!u(#mm|L8=;(Fx*kjY!G!sa1Djl z;f3eY;0#L&Qb-3QnJy95GElej*;y(}nvF>MK{~i>fdn7fNmAgteur3g(-h%g^Z<}b zAtVkdNMYwmVMzw&NYBt2izd*h4#+fOt1;fIXE#+6^MU->kbmL9HHzw+$HmFKhdTv7{I>Vnc@(qsT!q%$owe9`!Xj6EaK@r{@|DeV=ljpT+<*2OOP?LC zVCnU^$dL=U4aihmat76jLhs#AddJVKUwUT!>f22DTRCRY`{+zI`+)^~qOf`W#oimg z-#Yi{)^TPi8)J6b!i{&=^A>5A&FerqJ$1oq0E8W5J;MB#&m8(j=@cZ>Io*f>&*!=9` z#)}{K{(8Fi-YYbslNQYP%-P;^FAdL4=;%e7mOo9AOC27i(0Pkt>7A!9vUY-P$1k$< z(2XL<+W49S7`wKDby!5AW?={wF}SbFcN6Alp_rnd%1FdU@Py14@w z{kMPHyY`N-^zEzE*?t6L^XWhIF1)_}`6>F;Q^i%d+?~I6Q&j5*^i0OD04+bTLubdhxZ*ix(Y3kaDI&7hiV-!`11( z@?P&cXy9y#|6Hdq`p>cZ`7F*{&-+1Ff@9amtH;?J?0meQMEghFTZPB}Q zy!Y|3-n$>bNa$+xxW&d_u54U+E9)pdaFM-c8X|cA$@{%CpXJr+-o>Xj-hKl9r(+RY zub)}};(G7gA2o#G;fRet{b~Kuss78KXAKTB&1zYIO*8cMOV4c{zt%s0uK(;?f4h2m z^WtY4S6+ZG2zfvIc>U7ry=TsCUVmfr-07^$6Mws^|IB7oa&7Gb?ixI zuzv0O#*61ijz9eOu_s}6z4xE|+tt_aa|a;CAKL5Dr=5dvoW6hZHeu_DZY8(i;Zg+ z?5u;=fAc+9?#6FEqA(!b?cBpaP>z9r(MO)5e{Xc0jdMDmi;6cMZ18vI0+442IYItyv69~oaJ|?8v3tZ?7elFj!@~-BMtpiFZ8Y+ zbK_u;IbGmJi#&3gVW0-k^u~pA8_z%0d;T}QGvL~>^-F)~zkR89{kVW;L$N_q;B^0$ zPkU!hQY9^R_7oHAz59Ca&EFb?KLVE-H;cY?>{S2R{~Gi{E}-5x|Lppu5Bn#7yZ-rG zn}7Xi{qj>_LhmE1d-Wn>jgESkor+okH zv5hMyLAuRz=d3}-|E%ks*Yv1@VEM);n-|~TxbjrK#s0+?H@`UE``u}`2=pg`ls|uf zpatve^waqJVi}Tdldgs@|d9d@^b721Z)z^E^U)p*NGC7|q zO#^L8Z6J-dwSaCa**U0w_I&TmUjY8*2fq_<{>?{u6|8^y)Yk7V>^vj@B@AV-m0?Kz zw?FG$J@enkp3qkEPMr$i*|kaT)*oN(U4EYw*ZyD%9!x`P^77NY4`1n@d4A*F%YxvU zi%dy^{O`(X=u(VbugDKFa5mF z4rc3}R|WCm_x-J>pJV#{V;>+U&EB!`@s-~1(R|t0+IM~iv3c>=+GQ$&GmSrgcH@(G z5VHEt-~a4N?-^-h>1R{+WZ;Y{XP^3e7tX=iV8?Vz1txDo+kNk6UAJEOgtpQz{_EGy zZXP?K>e(0ntyfQMUcAzOi4CFKyQ1tp^C_wF!}{+@2Vh*`p>*4 zGTWw16`b~z?yz@!&Ck%!eKQ$;&3Ea&&;IOW0a72eF>n84AveEx0R@8g+0*x)f9^I% zU0?A5KkMw~8rtQvy%Q*@KIU!zazD_B#NMx6;{&~x({uwdAJeJ_AL=vhdQ|mHmF`UA zblRZ_C-C`r@AT!~$v+}#IkKSR)E-c$3o|6Uuk$c4sU7cbeDIt&)bpo>5vIqxmgyFXuk$cNIrRmxeHIv8ZN%go!FvK$SfRr40VJjbalYVT^8+EzF# zL-E`tAoY?{Ozks1b)GIU_*l zj8ymXysL@IGIldiS;qD&K|fyl@*LyUU~m3bP*%wh;mZ%(9M8(zs&>5|^ax*IS^zS; z9<+aDne&phc5}AI?p*bqnQ9+D|6~`01o@E*Lb4*&IQY~4@*KB@(uFb8l0Hi;)i|O6 zhmy)Abhm3k!o9SFLqmt(L;KVo`-1mvT@iYa%U888Kc;(qdb3jv3mjVJs1f~+TB`Q& zDimA(^27RyR!Ex3z*wchj%JS-tc-YOIRvGzerXG=W!`f2pkotVm9cckSiatTwZCx) z(p<8}t)iI1*IKbO*z8)6ldSjIA-e3Uk)_o+yi*fdyR+bF2}iy5Qn2H1Uwfs#d@;M0|SExP#E#ZqYix*G?U~&2E0`uFiIekQueM-yO11Ib+tr+5(8d zVFtTGL_eeEEPc#%h+=D6=bQ>)O3hlF>#^6NS?i(hibJaG(X`*c@yq|^pzPtUSn-$;P{^5+ycej6Z zQt7+fKe{z^quW0ZaG9sg`Q9Z&^&Hv&YKHbVQUS0E9t3`0ef#Ij50_0{&D#gL|Ksig z>GZF&5YiqkXZAskyNuiex@Vrkcs_RVaUGBFvtgg>ZNq=tm0Y zLqo&sKpm@>*#@UHMN%@u;C(#U#xgSuqFkYsnvRRkP3NY0qb!eH2eQ!ur(Ny?-PdYz zf?cD{tb^`GkfmhiL9{bn4kB%*fiOL4_uZ|af3jOawgbw}9XaiEhcVGz1=3P)Hz#H} z?uc@_^I<17VhMZ@GMuZe^4BhJbJ%`Gx9%5aIG>3oomw=&nO$xLsnfr&v0HL0DAm2W z5(RmFrB#fXwzwjya!x-NFPiw@eKUwNoLty%9yKPA9u{OXJ$TLRlzS}E>#*MjH_W1G zcFHt;xid>TcFG0pl#h?CT0B#{72Sqc3vL57CWvS2qS&^$gtda<&?4FD0N#RgAwlSR zVp6~ z)!PtkhH2yTcq_ztqL$X8Bmgm%O@WGVmWywA4TeP}>=G`yOB4%m1*>1uHGFxDPS=|; zv)*J_{1_t#EsYi|9X+ea2mm2f^gJ9rPMx*h!hCZF>vCBqs~m_VSZpc>3X`bCcF*&; zg~WO3&3mcqJhXJH0xOt*CMmbw$KQRHjn3B1@Pw+`iTMEHhX7pga*pWnm&`_>I&0#H}Hwm3!*bTy$ zaVXDhUErb0e?5M=-m{43cP$+01BgFGE1&MWLz%ZZu3W(^S;jgkz zc*f*4anen()}HXJ-kW-TSZI3QMyFv+32 z{QpvK6%I;xmKs$_%3RdrH=MAbjE&$=a>0(1bD^XIgqkKx&h+)9l8&j%b*zQnA_#@D zc574|iAJHMQsPg^%Q&-7@IXsg0>K=)p8lkuSL9Qxa&$qGP$8yR2WW&YHu2-sGkrcDRhzs zq#zWx1V>z~L+tA=haawd zwQtmK&B3!iCg#;|z29=VV}r;G9)+YMiVc3^0|Ffo^c~dJUm=Skw~8sihdi-56dMte zxEbi5^0jFndMr^mLJ>mMesh9V6IYQPb?R^Tz+U!@5UyP132?tO zR6q58%lUu}BF_iVSkUrO;Lxw|%8wXI6qO?i_9$L?MbRTzPWD(tF+yQO{!7Eu)&o5b zc7Wq*=>%XxR?wcU33k}%faOVcG>VkUK8m6WzDOs+(sKH!&_akINGjcq+s+!d+?D}4 zsk}WCKSARqzN`x`Zdp((jKe*;rp8@c;Df?yv%S;yjj%43>pFGMC}-%A7RzRmXyK*U zLXx=H+|abP#Be^84p>~E_$!DYqMf8~K!!aNT9Q&BBPmUYH23DpI1q$4kC5GDdhQk> zq|Pwp5mN8FBV>q>4@(%uIM{$^pot&+pYGbiOsC~Ny3lHO?<&kMFE38qdFPQMM~X+n zVrS{lok6Koy0g1_sNm^f@jabK?<$DD(TcU?HD~WCq;@Cymq=qHh=pv> zfR*#-g4s|97G0xRQDPWHid)|0Lc~3_rJprtmpKFPS4xYI%67YY@AQvv5p@ktK;=nn zkhnXYX(#>1NIZtdZkUESDO8~*y2p)=7q!{aj9NG5VR@x!mCf038MRfEX6hErHIX$W3$Zn4x!QHo*{T8qVf&b5yOuSW#|zh>#zC)p zY`i`@jL?h-eu=FG(czem1t3dS$6@VSFeaz6hF)&OuDd<5d;mJrV5^bhQd-AeX`a12 z!T+#N7-AY!(sB&bwc%ir{?&-=BSH!vSu!X&jS-0OZ$67|8(!jiQ^5i*D)OM!Y7vRX z^lAH{OCUXHH4Bnw=6UKVfIEvoO+t=Qs*D&w##mrAJxhPUS|l6s%_{>(?(QUC&8}Po zkH?&wxdW?*_S&}|9R|dSodoQj7DtP@|DwA>2k;x#KE#*&U#;LsVRqtsB@TNjU;gPv z%cKqwCko=4I)+XNgIU+26`osZ+gJPBZpZHlzNXuS@0&O;6zLP!ez(c@NO3R#KA52l zxUuZ0YJN(JgMs{8fuiH8>J{#=W(HXkgDi&iIN?feBc8}id-h)9iSYE3$=N#!x8FXt zbk_qj@|=BJlTUTG)y8r?3SN!7tkr*Ur-0L|ZezGLE!F*)%gS%x% zlWcH5CWsK4#3_Rzu{SkA8L^ELhh?i%G%F&%n6_F9Zlzd2`biw=56lQ@kFn$e`(8y> zwLjJ&8w&bMWullTynHqB_nm z3KWuCoCwWKrp)4TLz$9xSAl_YN(xpw8zQI!5JNvU8 zOTl54N6XC}$^UEhcevos3)9Q9O+w!+5mAUx2t3v2SK5ciaaYA=Wci`JgOpZtrd#;M KFMe_Rzy5!bga=>% diff --git a/priv/static/adminfe/static/js/app.8e186193.js b/priv/static/adminfe/static/js/app.8e186193.js new file mode 100644 index 0000000000000000000000000000000000000000..207bbeaa6272e593597daf30f018256e33943b6a GIT binary patch literal 137815 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 y{0&#~dSxcjNjro z;V2SCg8P8uo!yyv=4GF8uv1!^U9^K`E|Tk)&ggu0=H1=h)jW*y!fk@9E0$~ueLbGQ z^a-2ul6|*)Zdtr4bmEoKf#<+oShB*w$a$+0&n{hL0|+m-!j8nO)FOkJ{pG;Aw;Qu# zTnaA^2ZW^sUszo_Tzq5IR(OaXO!s@9m@F?m$hb_6kV>ylH;w#8x#*$u#zN#gZjI0o z`^K7;N+D|Y?K!>t~gYf}b zBoK7=R6=zeM*ae#t?}R%37Ng;lkl=xn#^W1_jD3p1V$aT-|^Srf61T z0iz**@UKiFQh1B0(GQ@nZGxGG-3T3qz_(f$ixQ&~;Zcb<^>&h|j|f7}Ml3uPd8e{Y z1oa#J&aBrdv>Da88kTsvGgWr1g9_nZ=7sz-1ZH^XKHOsx*jeBL_Q%hUJPSEK{rW;) zurTE5?Dyq+NPJ);5e9S2YyXOWdh{uzXWt*TD9B#3x#8 z0}288u$kgX)f+M;Xm(OQr{Z=&l^=%laL%WLeW=+|DN~X7-fmB7tYTcEV4{2X4 zmPX#TlGSr%uqQCj+Pheg%gxbpC`DLRIG{ic@h{I9Vt0(UKiRhxX))ONw;m1tv5S6q zlngJ}P>6J$X#3B;9Ob}6AJBEsbzv{o4io+Kcyxv~rfuGk;3567Z8dGDP7+*2(5~S& zh8CmBt188g5|i3glZtd?l!9LS%~L!E`z+N#4e)P91G$X}Pjxcqk4{beJP1&`wgNAy zdte~MB8z>=MV&aATxB_V-c+c+&9NR`ktE<8R%DfRYM4&AOJScICmTqv+5X^VFP|ES zhB|9BsB4^8ErniV2l<$0uonF#%~byXQ)&sBVPpGnZuLN|M86=QwZ5+j%#?2GkAYbU zeGwRIOPDN8XaGG?J*y`_~`PZ zzg~N+8(>9KjxTf~7EA2NM-6$E!VTl^3+L797W*>}STJ6K-vQ{hS7JXsWjfO*O()$v zYHubC5OJyDJ!*lN{o7_9sS!D2ajoKrf)K$S=k;vW*-dw0$Fs;Zx+<0iy(o>2%Va}+ z9`D8hlcs4#LK@>tfy@Kfd+eEG14)-SS{}v^yv2`1W_WqSO>Xh>Lh6M;9j3ktCiHy} z&n}WfJbGJup!BItMQZ5wIY&V62?bqzI8LMr3BrKQ5w0{2B9TK=iMq6J?qM#?S!3lP z!viZ0Lz7&aLAZ{mWI3XFc5cE+sCmB-9*2pJHw#M~3P<1E;Jj-W9&SAK6P(12#uV-G zvST4)V-4@=r97%JIH>CCj2tbMCc{}e$H72p4fe&m*RN=oBZF#5wC3zVxk*#9MJo-5pX@Zd4x~ zx`9V!Xh;K?%6e3=9@emywhDHO!lq;sT2wLF+O|6PD+Wd{_|=?0m~vg93+(YUc`QLr zSoJ%+?BI_U3;KLAtBNz)7QikclCTm*>St+$uyeetpA2 V{4%5i5k_Lq>BY(3{eB)^{tG;yMFIc- literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-1fbf.616fb309.js b/priv/static/adminfe/static/js/chunk-1fbf.616fb309.js new file mode 100644 index 0000000000000000000000000000000000000000..5ad34d8010a1d3d58cd9aec26afde826cacccb75 GIT binary patch literal 17717 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 C8JNoe literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-f018.e1a7a454.js b/priv/static/adminfe/static/js/chunk-2325.154a537b.js similarity index 98% rename from priv/static/adminfe/static/js/chunk-f018.e1a7a454.js rename to priv/static/adminfe/static/js/chunk-2325.154a537b.js index 9c06e442c7282c5ee97330ef28af74f3d60bc5fb..3fe9add8238b5951211aff3bff5b98515f3cd238 100644 GIT binary patch delta 15 WcmbQ^Fvnqn4U3Vnk?BTyN delta 15 WcmbQ^Fvnqn4NIDVp~XgrJMsW5WCe5p diff --git a/priv/static/adminfe/static/js/chunk-56c9.28e35fc3.js b/priv/static/adminfe/static/js/chunk-56c9.28e35fc3.js deleted file mode 100644 index 6f92e0e72241658dfe8ac60425710319ba5ae0c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14105 zcmd5@33J;zlKv|SYimX-Q?ecBluJA7*v_+)IEv52$+}z=2}zWAg#aZ>e){j*jcyX8 zBzyJPn(`Y4`9M->lvD{%6 zjhj!Oxi767`~E0PUbOpJdF?jY}{L!6g8<*-&NM`#7S#uN7gOXeS2Xwc4aH7 zr;V1gu+O65=asoces8rloxat!-fk+_vh}}OBUu4b_}3`vKB3{X>CFL%w|j>Mpebc+ zJO!fD(UUhh(RfNkWh|Hh(b0#UVNMjxh^UN(4iN3fX9cIwA)+!Sk!Ud5zsNaBCMshp z0;1ma$+MhDMZ~Fu5nzssXFY#?_mQT|X}AD-0)~%X93JT5o}gg^3}ATpHkC9ypkV`q zFq~|r?`SxrVFTcH$A?{qhIy|Bh+%juj5laFrr8ESwK>OLpN3N!HUR4Q&DA+cwI^w~ z09=&k_T6Vvy34{e0M7of_c+zeU7l@#2@LOT+|kb62{AVSsy%or5}M6AF8~kMKDaxb z=wXl7HUP?8{S|zoVbOFH0CFQ68-NxpW9|@$vYo$!x~TV@j4yR6h1`( zhyaF1m*QFvi-2YuAZnif1r&2az?CfL* zYZ}0V;g{(d+26n;<_17}@edC?&3wSdVt_bo29A!t2X9k~R|Cd~lYvnePfo6Oh!g9g z0ETG2ch8a|Jv?O7H2~^j=Wv_C(vWpw02KE5vw&nfInQSwPHrZ3E1j4hHP) z^qS;8M1b~RU_J`!@?dzTdH5_S1EBG~x*E{&e70NzprQ5>pYB6nfnE`~drPrS1GHcX zV<4Y3LQTGU`t-ft!H6|!01RsCa-V|hh=W=IjB)nyEA?5=9`kGijB!7oLJBeCF|S(1axVB7o<}}P}8vqsaW)gg)VU8dMK%r)zrgXUkEYt!B(Q4mb z%(wLHkge7LXtmCPBNNr^p<1@o8KpED zAdV%Bm&j+OXu-kkjxO7jE!Y6)J;A3r53~0afW)}<`N=8Wfs*5v0Z`1Fn=i?8C5zbr zXu;2&tCw0tk}cQ(Xu)E`Aqh&hU<06V23J>aX*LVT0AFEv_Thw*X!(`SZ2%P2{O;K~ z&4#;hmLkK$jo_*b(Xcg-Mh&%y}IH$!vJ`T9Cio1 zI_C-o2%3pbDCRyzD1`ut=fGe{GT*tPJ6;7$U=Y;9L3~7aui{8zfH^8z>FJmcIWKYsb+JQLieikmR)z^FCTD}Di#~aMCMcoN01+7stul4q(S|d&N(10| zE|XIdTE^!w0A|1MVs^J|o+mhar_Ww!EigojmQVtUnUMFx-EjVzCQaCN3gE7pNRjEp zc=OX!ids2FoCJ|H4mC{UX-%};*b^P=q-E=@)gga9U$Albw9|dgGo)yS#tW=KR9<7p3W+B-NUZ< z_FUOYLHed$H1#&mtcLA$s9|JBo%_fM1sH*H6f~G1?j~uR$To-xCD6WCvqZE>SavGD zW_~KX_M@%E!VZNR#vYKmPU0&k@aN*SpGx&kC?(R;z6zPEmOFIPJyqXov{ZbVBqH5+ zq^LJGR7(cFE9%>z380Avf;Lp*f?Y5>ZQQFNq|*N-Rh){J=gY)V?hs6-H0j)p6S#iv zr9RWK*H*SK&qXACdfGIJyvb3L-n) zjII;8A}FKa5r9~>)`m4@1`815P(<~Tb*~Z4LFq_UsT4;Si-rv|Lm{Oz5Oq?zB{SCr z!~#ug974WkRdeGoK{0t2h^*0awF;`6SYqWzeMm-D_~=tHn}t0PDmTLmUj=2;&P~WV z)7laqi&MyU&4N%6!5-?W6^Lk{hPGAnl?dyyVSz>yCzayDhqaXxCMAQ)c|zQ3Ku~J+ z<1_>=);0WTo}4rf4r)h7?Jxu;VC{aV4(-;_)1y=HANc9*k+)$r8g|?v=cxNFr%{jW zk{B=)Ds3>f=qRw4R5(f;1|k%ZvcZ&Ew^9WC)~);Z-@-&oO9V|f4gv>mgC-sXl;$Xv zf~P4h7S&po6dav&*&-_w67~#X>^4{(F*_861mHZlsFT8le-8n(Eg<8)m5M6HF2AqkboV2M4Skf|eK?uBLiwG9rB_PvD-Kvod40j%4$XmtOimU5csP4Mq ziLoniX17SwXxzYmRp!u7t!|b#W7)jLVJiBiJ!WZO!zsWt+SY9^aH6pVHb6^T{~Ogx zfBpw9)9Pk`w`y!u$gDMcB9*Tdp?<57cv#Vrd93{x8J2QT^0^J;g;IntTf(&g#R_iR z>{ss&JO;dx>{=S0;B>IFHju!@Q56~3aAm1)@m_mrfqKl{px0Shz=P`%-glsWFAkLY zg8^K4mJ3%H37wAJ(_wvCjqFGc39OkDv2?&B{HSeNEEgF%0fc=YY#yqrpou>;h36|H ztBTT4$*kO}`1n%QHzOPjBN+7ess@(xcOVO!LW6c1)pDo_XB@(!D^>~wxkQ=})-od& z3IX|G5fe&4#ZpM0ZIWD0l!w0v0?|ZtBgi#S#wLivyBOzlI=3kD22dmfut!^VS)rgy zj*`BoWBOX>cu<6n=M_l=7-7|0^sK6MR{h|29c%k{9xD}LJQ3eN*{a7`N!9~(SdTiL zvY6TFf74-0Qnd30e^HUV?T1vj?x3j;SA_Uao|ISo)uS?-pEzq41-``G?mws2V#!}T zZNcZqkNXSphLZbpoflEO`L*~`=J#NHxv{q!#oubYfulTpKlfs9#(5BwOn7^(yTviJ zg51=yy*T_pb)X+Xrge02@($es^B1Op0J?Ph{%FGTgNaIUja3tP+=0%cy;}#G2PO(r zzH$Qv35W>NkQ@8awjE_bVE)(GjazYoA63ZK?QP!=pn*X86S6hQ1btT#)Fx;;I1CwK8qR4>&#tG^qnkF z`J5#6Lnj5Z{cS~@tBW{nxj+J6uG<1r6;Yx8Z`N&!O(suVWVwW@43^56JfX*Nm;gnp zYAqRk5m`#MZ$qx=>RJ*W`Qk)pgcQ!Gkb9suqH3$OJori;I`D_pqK2%isf*8|n&C>k z7Dp!GB*LO+v;I;z#FCL0dLW%xBQc)xP;F^JLovdH=#TDOFY+^c))O8m zhw}jZr#H=U{>QhiCsYJoM_K71j@AP7wRPbLxo`Kz5S{SGND9Xsug7 zAc&<1TWo^!KJKyp_ZB+sAJxu2C8KTAyP~e!FPt^cUHO=+mENB|)1C|O7Qf5hfE9Np zf3vkA<3D6;de7Kw{D!6Boq%sqtERTDXn{8?%3$E)&D-XdPHA#J<{BoG2es1=;Fo#q zVN(F(f4F*R?7A!EL%BvUB}CS7^TNPRI`dh z92%cImvZRjH|5aqCITwDf0Ffa0~ z@3SvR^#UtCX7zecc3y75$KbkHZ!~tj6;ER$WKk5=`lJJ|sHQS6`(rz^E0fw@?vzj! z!<-DdTknZ9!B@AuQ311sB>CFU`BrCC8(wDLGoJU-3JT zT!@cau#uvceyH$Yaz&d{yA%8QsSLU+K6-3%WXHU=Rf+P;ElbtrFSz>Vk;9 zT6(Tof+En$3i-+$p!BU*jVWt*^@14RxAfhL#WwdkmLqk6FTFrZBSlldLBf^O=RFe- zJ~4sEu?f8Gf8noF*yAiab*At2_bQWSf#m_3fl2_*i553@@vO~v2Z^99APIoyx6JboT>^oK zP506gJCEJxo(tdmVK)%YEh26$H$8cA|VkG2`~hxOBDTU zUgNyLd9Zns|J!?4p$az=04X`ibkB5K1W>nKyLRpS-ntILQFQHI`)4z6c=>%Cg|oeq zXTSdX;p4VDTg2n74<9>YP{=ZkQd1W~w^bp5Wkeb-sU zz7r?&V3>5izVhZyu;*=czIyt0zq9?d=Z0Isw(H$@JD>gh)!VwQ`@{G)+xm+)?@o)Y z(d`#!f4eEZD4*2z#W2?`PqVNjbo;m27k?{ud*6M2oIEXjUq0H+S0_Ja7V&)aQ1>hsquyj|d+YAL z`}XW7f0%5|-Lvhj4;{~ZdJu)@!9}M_6P&9bAGf=A)+c5$+jnz6Sn^#SVUOd*aEK=z%%7k4BG+@1txhcSk6rx%4Ss*$9qw%bQ+__| zpQ1HkeKG4FtgxTOCLCV20Tc+6Tjfi5JJc zj(;PFWqE@;MLu*g2m^QzzojgAjd&K#tD#$L){Z zXSqSurj!HkU3eZ%CegJF;Ex)@Z=sqC1pU$4Ak25T1{7seow*+`CJ7+v%=~CJ@tq4f zFpeGyi*63Lw~OQ=N;jq{+C{4MrVuaJ-x@#z>Ye)|e~xpnP84C|`grz2uncEw6py`2 z-${b0k7--@7KFIAcEZK<%%A7aNfOO=rr!J_2vb5*cAN#52k9sSHA**5{8y&iX0_@hU0zSrLYA-V+`sIam*F=jj0f*%!&e)6fU4RF^LsKE*`SZe$ zNf@p}E7g^Kwn!2*NbhUmV`lRJC;3*NyGby-#HFm6CBk*N423Du!x1jffARWb_fOBd z;bJl||Fiw|%#CI=z1STL&cTK5**vj(weUq^pYF|E+_}*_iMykedtP9nAueTH%rxKS z3^c9~T)p1DX%uPZ8E7~1W+_|k;gj^o!UtK)Jc;PnXXyv$-q1gbqRaHbMHF33{Pbsn zqmrb2dbcwThVv+n&J*%VU|6e4H#`qv+6su1dt7$V%3-S0`9wIaH(op z_N^=fjJyU^Rpayn-9kgIs)2s5zZbw(eQksNzN?^K^>JoX?s2=QJ*oOW{Xow}3pB+B zk0CYv_mPIqSsG#$+P0R6SpXV6qySWg=YAs^0cM~z`SZJpE-am6`Zu~!Lf)TFp4v)fjo0j*4oSR81Ved^8 z`kk)K7*oj$Sdeup8WyIY9$27?=FaY}^V~o8NMIn5{>+2MmuR3hS2cF6{??k{>*xE& zh1t==x-%+tK-19|X_2{NDLyNnP69x?1jZR5AK)qAG{J1MIIPtiy;7Lcgvte6f}jJn z!E6GN25mKdv9w{(OLi4%34G4~Gtg~>dFIazkzTG8V2E_6tF)IEd>hT&I>fZZbRn+u z?X5FXm>MKc;{P2w>OZ1sfWC@2uZ*%`2-S;GHpF9CNyf=^LM)b6Q(TXO;n*2QbFksF z2(lWazvf*}g0tP39Qj??VRkhr9nSv+G-owwKyE8d z`%NK->9GZRoI*021aaa-=Z+uJ#XNFyC}aBn+BwS-3kSp$&zc|XxBKr-Uk(o5zUjX^ zIy@QlPfzww55IeL*tcki>D3Rff_W5@^4NiDIiP8}&Of7tGlbNMr#P@ocViMTLF|;w zO=2k_x0m#k-gGrJd*b!ZqsTeyoq4}JF_dIuw;V}Dgk)0nih{ov5w3LtMv!G5`XZ z%D2FD&`Nr!)(2b@bvZpGScLwyo}vCkYee)K#SlVkCT1ct0MsS)fG5hj5*k+BW%^c? zD|x9Np4-!1rgkfuH)V7Vg$!8at;zsGXzMDfA=Ipq%|nhtM|IGGc*#s-ftiIUHML7Q z^UupDE@+X9d>yZOj8B`BZ?#@(++wl3v4ZCgbwTLC^r@Mh<`^m~YildGS6(G)w_2}~ z8n;~~we32-d*M2t|NGw@(4enA|Ek4W`~BC}QkPgjv|>qSH))WJ-< z_+tU3>a7z%#vscakplun%hjL0?$=#?GKt%-9*x&nJxC~4h`BCVKails?tcrJ+XBEc zOegWYHKtSJ769P$Ol=jW*A=&(jD~yujRzcox4>`@I%bPaX>d`zd-c2~bQXa!$2O5& z6|qCxwy+`Ne1MBuUBEeBfKLbAlL~y-xbXDt>(uA=h9N^w!A)2csQrnf)OU96jTwe} zG$A6)UD{Y{UpB@*raJ2a51GDsI7U*tUMLk>PEH`vQe#vTX4C9iNrw)bnPN8T5p%yQ ze=TOtRp2@P4K^zDCQ4+P&7-RTHfKwTvBkH@shB*v&I@H5={n!BQKah}X-zxuC>grj zuJekH7RefH#c{wH(q@i``+KKN3SUF=0r3WbR>G56grJLOIEOKt7{^I6i+j7f7vTIB zXD*KIZn|UEU)RB9u=^UE>rQmO(>JnacMfNlP8ca;VhF#db05l;IoQ@{<`bLW1to<` zLazg70581ctq=>CnVjQzS6+bqgZqM!>s<4JNIY3G(rz=~M2X*Xd=F|MH4<(%Y~(nY z%>YfXyB>f@@(ND)$j2IBr5xUVO}h-SfOIesxmYli&0M?Ae9`=%KdBTr_d2fYcARN& zLz9SIjQGUpvAPB_j7T+U!Ls3$rN`06BuDH-n1M3+R8Gd)rc)9fSmpshqs0X9oWzh? zX;*Qd0=_I^Y+$-6bY|llSBA9UW59!58{(Kaw~)$(qlc7ttG6EPOgei)v4=vix&QM5 zLLSgeV-_?NAQoFVyeYBJWCEmwlwpuXwYWwPw$q6^&bK~!GKC}oe9~mcL<^K2 z*+K79u;bv=W(zoiJp78MR&w_Os@#iZzj1mWmg3CrIZ7mm6 z6pr@lGH#D}FCd2Kd&Hpq3Th9BRG`odstI-MnehAJF1%IYfw?K7K8HdQo=J0d!kEo0 zs%345nKV>G@Ykhn7~*<8Lv(}l?&LMm+q%f4Z?pf2<31mdIQqYKS<$(x*14;DUiU&F zu&1}SSwda7$F8Qc4EaAS*!3ziaMxU|0h^-C8lcYW2%d0!lfZA<@e=c8Q%p!Py#(UB z{}XT@1f&18dw#Y9WnmERYAf9CCh$Y?a{0+u@?c~ch@e8Y<}8;m%)^an3snAoUi*QLA z9Z;j@8mqJuc*>;Rh<--9b7UE$maZK7HYzA7^ozziifp8YzQ3Bn`v7`X*bwVzzVuAp zA-BQp)g0U@Ubx^v$!dJ->Y2NIM6nHN_huWiTd)-K)PiCkN4kbuKffqx_n-??Q{xzx zq84oF;!b=q*nv5HwfcahYXfm(JKtb24<2S|_6TO%imPjRdQt+YkX}2atLJN;om0_; zH9k7pGv?BV%k?VnCpA^v@#0T2K&y@Hg_^xNKGpzcE1H}jy{@`vsIasR9-_+Cdpi(AE=eLL2g-g|7N>3c2-ixzHnU9H*21lRHS;qLzB*R!{;WQ`=>cNg=KB<^i(b_ ze}FcIYOG89tbk|ocugb|;qWu}sdKFCWlgc|G`fUh7vWE=YKH=8E8foY1SbAcaWUF4 zTGrqu)W<;eF$h8(S-F|ON)5kGei$JOSwdH^Z)Jn2$<{In5CMrmQ!-9r)7haJ9+PAM zqyX!f+?%l;mK>Y;wM?GD=wppA~s$b*rU+Uo)N08u9zVMk2? zOd%^8Q%3^aHr_HRbj$i{0a|f>gAtYV_ZM^cEsmU@qBGLs^9bsELNP?1akA*x)ln&g zurNVRV&!7k3~5W?iIV{X1P*yqLQn<{&;#jg_w%p(FBNIn0A--w{(@`^OZOrjyv3%x zQu8M0!cNTuqI6UEjOMoEvoGM-x0uJ`^tob39zQg8`|I;!Y^-rKh0~=8kG#t9_12P$h7j65X$VTYii7hz2j!rS# zd{2}Ht{ZIM1?O9TdP>=h1Q79FCj}v%2H!kIl;qb89M#_&#LoMp=ZGlWid84~K8Uz% zNbw_1L4=Xg37HNo;OOa4+MaMvWqXp`L3W0v6hZYLAN-FWypLU#t|&mdqHURNHoZ+q z{bLH5r@7&)G8+AU(j*NyFnDqQSo=QPyAW;yKA!0& z-P>@Yf~gEHRQQ`-XhwAeDImOb;f=rtPS~t@*=3!Zj@d00S*q^t3QG?Nm_>gqf==mW zmbl=q55}@6p{y*lNq`|)2O)D-7F%Huu(`_>$cKAxv#2MRV+G=2wEAfG7O_fm@;xK; zLbq_dP_E8->?#o`Q{Ss<-OtL6Y{jy!K5VoUng8U)NDnamrw zBwtJG+DK)t+Dd9>dTk+V^vO3?32`iM_|ph(c6A+h#9MgpiFgZV90F5xEJ42l#^s`@ z`p7hez@*jcivoyaZn;VDN{{V93uX*wG-A5%Eavc*V6R&4)~gL@@|7dUZ?=Z8*9&Ed zYZ{-fneiHsRd=CoQ5&K*vs#I=DTA8NN|@3mJ#Kw^s4y83l$^7TFJ2`|2-qhP5?aC` zocu|NX3BTUc~p-#(p!XZQaF>7s;=%?fCqTlo)ni0 zA$ef8fegEDZxSTjVGCH0N=P4FC@SZ0w?_~pBB@3SII*)e^)5mmF`>ciJjVadhbmg9 z#RUafJfL*Fh&i+a;A&&km1;joCN;8@7DaMO_F5*{*!>C=i`Jwpclh z56aYkN@ZhIe`kAxRP}eEReuNG3@Iq#kh@&(HPN&TQz!Sa z8gGs42`XmEJaR%0ry(f$>XBa)L9k=kWMN0?^rg*eKA;BFq<;pNPL3uyW=t%siX6^C-2Fk*`7|S6 z^%u}B6fedVdOq3@nH>U8=2RnqWDH8YK)a&gqqm^gySjF<4Dg{nb1N07NP3y9Nk>w6 zIEUeAhVFH(EmP4QDxH^4gY2q|*cR0>yXaGkFx&w<$$&z?T9cZZGqtSVpe)WMk zNIF54T;y$mi#(7U$FPtGd$%bId97KZzFHg)zpd3U6vwQXJlM0;3L6GhM3oiC;X73AH5xzOFf;%9Z# zf)k_JBUzk(gP?tiFP$V9M*j~*2 z{@-6)DG*bt|9*@_@kEAiovC;0Am%$vB$X4m=P6v+U^w(gU1l~yBoyE;B_^KDjhsks zLa7%yD~2@~Mf8O+C+S44cum@Mew#X1ALt&TRp7Gu>Xr(lPe~w5-j`!kp zBDBl!8i|pA8YxKt5#(k@Y8PCe@asgMQxi5XY&zvxphObYZ198gW6KO~kW|HkAR4vdt?1pbfbz=De~NPtc$P)-S563XR(3=*FB?|m+l zAvBmSC~*oZ4+3Xnd#S9dZU)In9biJdDdvbOEc9n>wj^@|%{HD-ybCV#0A8BJMA)M! znFjT2%0h5RsW;J>GYycPlH^CLAyobK^K(+77P?qn>B)C?cG5m$q`$<{P#EHBcaB?b zSHur*GBBUeA%KS;C;|{dMV}MDQsnwuMsKCJeu1K=Z`LH~hgd!k7^lr9$Q8n0I;bRI zr)rhmDNsMaRS)kXC?lzk$BrbXL>V;rE;TM=Lu0`Em?qR91G^USh#x7)ef&^~dK=vy zi^C~wko9iOEmCW9Xc=jcHsgKM>-P<%c{GNP3ZD^c<}T$QYcKlAZgi-V7S}C^nxsor z&hfndc!A*Ys~`qZRO;|LvPsUae2hcg3=TvF)`kOh(h?3P+bsOqDO*qET*4h*PHwj*vk=i7HDgOkJKx3<{oyh?DG&fhG!Rd~s$L00u?7s}Mk(^i7M6M5dW$`v}AP+S`aeTI}LJGQLq>97?mq z_ZZR>gCoG!5knH7WF6&}Zl?@I<`ri`*?}xzpe7|pqDQVe z-ROkDQKhDnfl(bv>FdPhZ3p`vQ|h=FOwa|gxNvrD0nePMKO?n^1?4zB=+E+sKpCOa z8~JAoR1Q_+$WLd7Ic0ve17jeJbt9A{zps!#9i#JN)I=T!VqVe7+i$yFDOsFssqCjH+6~kv!@LE60S6B0?u8MrywBE)?hn} z9uqZaOQM@AhlvMa7IUO1Kju=pq)*56c7RMaDbv_fzw3|&-31XW(*gf#(wq;CX)iy~ zK{>CweA5shU~}>{SUie=P%&t2)cfina4&KQiiBnPlr^G=uA|`j=sQ)dB))_lf&HRysS*as2MhtA9As zb6U;f0=mo4aN(}Q_mTjB_McLNLGy&KU?9@Ti{-wWCzb{ZpRwW$7a1&@;4_%fqN?U% z7*%;9iPO_FAPr9d8G)5!Xf>o%Vo*}0>N$-B=`bkCK}lgr`>Jn8^d~}wOc~{SS-w!0 zYPx)UPO4N~rj#7MzP_p_leHurFze9Rd84vu4cHKu61zT6vJFyg2%#PYnMiX+cm#Y9 z;#0lFTC%Lm%=9!$*c(E4RJ#M&PdcNm*rIn(&o(EEz&LKT_AcsMOT;rE;`zxe#KZN@q%iL+|=rBp-P z-I}dm+r8F?f$pdU9Oy35&52AaqK!XWfZ+(%FPN}Ax*~L^%|Jr-Gu6XD_pmm2$~tWh zswd(buWPmN&8zM(J<}`zC9?(V+UZV(LUc5bW;6PmZfD&nCo@8`!X~^9C0=hzJ|Lhr zgExt^Yr~g1X%5d0p`PXuAVITqEn;+6JJmE2qo03!kn+^7`SX}(M;6J3(5zQb$ku4I zt1Dzn7BH!_t1qOYY9P0OAB5pEhGIr)1;AK`I|+qZ8UsMVkj<3f+VYrHOUa`)ctCbn z^r2Ke{^uLW?_oJ}Dj7F7SWBE#Q)Q-@Y{h4&`Z1XS`c%|7&2Elk zC?miuTd=L87X~X%t>ol3O8b*THq{YBs!Bhslqf{-MyWX5lb>Z0YhL@S+AqRf5Bh9#-_WXF1<5TMxoN```Br~<-!1DEJ;Tyf+KqZu-mdRWrV-Tt zIaLr%RK2?Yi1H5Ca}?Y-jwZqIwy?N2(c784D(z<9TJO=x3)lXfg7SME^Q7lIkNi0N zumAi%u;)di;QSV8$rxP3n`mT0j;tUs55H<&gHp(;u9kQ7j)~2uA-7eUrJiZ9AoS=)sta_ z!mvnt%a5%Ug3J;;sdNClSF-;jP!^5_Q1PK$47nW87wq?-^mRaJDp0~8n!{ho5U_nT zqR7$y%$qhqq_SrA9_b}9Qj=o_PzzpoQ~1oWv!H-Khy26^%E9FIgCXR+g_JG^hMkn= z9w9NgcRY`7Zr^)z9I+;JqOz?_{$TE1Q!$4mLA^CHQ^c4M%@PL!UX-RaIW)k9fil~` zsR3{8cSAI0-7%azh_kb&&T7~OfIbq%t!^RHl#4=;f@X=^o+b%^aXlg~OUHn8tuv}V zw2tVf*S=vf_=kCS5zRo2(}wD&c~23~>0AC`zYFbm_+h=9 z8;XT^>FgV;)qH5Tk~r&hJoVG`3cbk$dLYgAsGrt*BygDc=Dqwh@8j42g8nvdZl;z& zmw$kP0)9^YbYJxr>3a=Mz?bPznTMuZ{df{wjLr6BpPH{Z2UIZJ$@H9gXudrQ=0^76 zALd;!-$4z=p_yI!zLdw7w`IcfWzk$pPdsdt0Q zdD`R~_r84EReFZrvoHNG4D^_Kn?69919<+|ZvJjY+2c(6h5DWE;Il8&@jv&!#OlCS z!c5^;7e;w-^P{?$n;4^{DvW=jqt`v(K%usS<6p3(Aj}3$)gGu!o(hrvP5lk)?MpuxZ#t~pd@0a)R6YBfu4Jqq^-dFc<3_hKt zw#qKj532hBr#-)7#1fZQp+nu z`M&@5jY}sy1aZFI>hy5kPy^_8Q=#PWW)R=TGLYR7Kdb2I4kdLFJ@TP*c+=NyVW#N$ zR$rZu_tq$XUtkTcc$HeC^lc_7KU=#EW=!fdTFVgEQIV&=QzX{C_9v5_OGMc*5~!#D zA0dSL+dE^!h54PTee92B%;@MQ$Z~DHgyb;1LRR2WB`2 zLQ1yY1mRhPY*y(M$iPWu%&kYjE_(rT=bIKGV&U1j*?t5mni)AY8%}a=bs35LZ9jqJ zlq})_1n+n_56+pY@9b zLa?Y5hL?Ma@)6)pY{;_kXnjS3*Zs%)?*1OUe9piBw|~G4aJ=Wa;nx0k_ZvPmP)wn>Cy zbIv%|BJ?7qj*Lx~p{~HeS_)v(Y%THX#h6bvyc*E{>~cUDr6Mx#N+DhPpPudQ{V4-- z-VQ@B9~T~NLSWF*@vGx6&G&bHInxuN+r#kprYPPT0yhvIzc;b zrw7fwPC1;!!ATG*GXqcsAt>2|Fn9M=B*EYAF_LD#PpUuvgC~FA?!M-`RUCNe>+fPi^*evhNpC|@g zeFAp|kb@1xn3sF~A4Jm`5>V`rV!-IqN&0UZKX5=PmcX%r@IfbSJU6S7W2XB|xtS0F zE)Cc4LCJ9*nQnRCQm+hQ*;e?3NIpI)lbx=M><#(`LMG4TwuKkea|&8?(y%=3C9@Jr z9ML$CcAEo|-Rl}K5_^$=6^tI_>pNo1gCQ4v=yeE&;H*F3;9PAXXWrt%WjLrfLG3M* zfvt(-lxR_CI$$MC!x&(KhQX5~XjQbp32LiNVenDq7nC_0f-QToMIo$lFb6`;0;29)R62n$oIh(JbNu=>#Fg*GDCtc>B{mK-HcsMxwuVo+%qhL7?J ztqvM}uJti7Lr%(R}B`ZK_I|R>B(twT_>%k|C z;SWZf0vr)hdQPcb6Str->JolX@k%3$`jAA6AMU}c8U7<+90=DjAWsl-ESV%pu>r_8 z;|u?Zc*G%mk0=6~7z)XIAZ#M#YH7g}9@mO>()Tyb+N~Ar)P(ReZge};Zwtb73f~`U zO72|nreo(I!R#!5^ab47oh=$`n@Q3aPrp#VfKHj#Q8mP~9aW0o=yCGHkI z>^?)B5;(6}?^$KI68D<9({$-kw+L+xj$mP}cVBU8nd#j-!k z*|PYz&zHru8MAmLXGW(jCC5U1SE%fM6RcVMFuWO=9sl6WS?oSGcSb<{y|ZVrTZccZ ztEr${gP`&+=8S5qPzlH15_1+)3CIWH&S=+l?=856-z|FZ?n<4T#dF3rpJ+XDIbDZogt3VviN89&XEq*JZNR9_+N zkwPQG;rtdhVHlH0IU5H^@=k^&gg|FvC%a&(qf3g3V;yb;cTW5X?weXrjxGeq`sW_f zaw9uC0~wLP}Q%M@?BMCcOaR zfGWgF2h`)ZR%gq1FKSyXRFt%?@2qy9%b~7ywNA{qp;WZhSMRf@pK%fq)nTnf5V@?d z66)A+#{?V?uxHY7i(RALAP9A(^hgU@cHBru&xlLn+5-T=NP#(Zf%q9!8*7d|az(GJ zE|(>s$wMrGW>RK|(uSw3`v`)ep|j5E0+v#y<2j0-4eO+@(&U@;Yuseza_inby2Gl4 zE?q!hu>&zG4mH>_#YGIL*~S)PcUrZWjoc?lmVjgpO|O(UjVu~2avvaOpuB=a#ZIJy77<+CD5Ur~H@sU#GtbEjKAYsay^7<1p)Ue zKduOH5+3c4(}3$}-L*GDy$Uj}Y*9`m?UuoQj%j0ZKY)-%j&=ShYo4qu>o)dpM$r(; z>FMrl9Qk2zvwJN6nvnQ$GM)TCk~48mzb@n@JJd-7t`>ghYYMkG*?XPlB|BnQSJYb(25=9_5AVop?TZaekBX$sO zD&*!GS#QBsnor?$^*qooVQ#)tof{)!>W8jkgUDx|g7P^uNDW=}b!KMw-O`CwwJrTv zk4sE!Wy5rV7*W<&`Ki79PaX6F4mAziNf3QI@ekv8JTi0FA#{JHGC+PB!?x8qHDALQ z3bC&l9@FZe>vugBhgaz2-3+=TzwalcQ-Wsk4!I_KewP$Vy?AST3n4ikb&l>4M7=nh z2ALgT>?m|9-yHxC;7kWuRK8L$%BR2g(SZi>p7N z!6AU0a=^=r190`(fR`h4Pi%8kQ?f?`cKyA?{WGV&^$)2^Ntkp!JQ^Um<+(c;{`#x` zwX&0I0mAZJGu~(&j<48ZKeP@^%lz{_d8HYt$P%BZj{=>iWJHFve=CM?K69kKquFxC zdQznIG-=i~HzAMY9OD76@o0xG0(GxUkT^xT$?xMPs4M;VxFg%&1nQr)U5L%SBnjSCEht1f=xbwG+iz_U{|$F&zB(o3gV(! zLLQbvtH1@K?l8N6YhH@Lxe}!67B7HQJzo=~FNJ%t1eyv%jvB5lMAKC?M=3BAg~byG zvgXQTHmm zL;;Tawv*GC72s=J{x5ugf()jx^x(4fMn6$8OtJ>(qt6CA+Ce8oE<1moR<$`L;}R}5 zac0!TyoJBv9&l^0jgWfdi*O4!A^p(#RO?>CG?iVtkf;~yG8FG?YeY6_@KBU5(_E1? z2U_!bR2z{3$Z_`15#0-#$2K%@R$Ydd$w5!I6M=mw4u|w7aSCZ3T8i4`!V#SQv*s$0 zEPu?&I7x-~|BAiM*_kSO(0CVbz$Kw0%{+6$8VMIh1AhQP|D zbF;;gku{<#9c;T(Z?>f)TelFUB9h7nABa@^{Dc3IlOGB2s^)5g7Qr%JJVc6F`{No@ zwc(99au-V{Th;*6B|8z8QuTHUFX90m0A3bom`Tc+0!72bxpeIheoOK^)N&`$^=b6o z60A@=4u3qPBlpdobDoZLjp~@8c7>cbANgsz{)cBDw<+h<{r1<4NLhX|ZFAS@^gaNR z>fqr33YLMt?&>KXEkg&r(`_bshn?=xOyRz+HWfcV!*puSoI60>c+(su<7qL1JXnpw zLs||3!2HA)cmwnXyP-uP^oC9V!nTIFq=PUpXFZA12_%2o+w< znYh}8B{NrRbsuQzZFURmDccID!DF=();5SPinb!iY(*aZgKpTJr|9qP?d{FK>40Q* z@R$FMLhV2whol?wSmGV?KBvHGTwy17$QaWPH5uqHMs3vK|s)3`f}BB(f%v z(hfRyzVuU2dP>$?l{)v1K7<~Xw5c7Tn!P zM)HtiRb@tSWXMlaMescCG*yzm8WTn8#pt&JMU^>YaKtxEuI$?@VyA@5 z!`}~A8RhbHNQ)049kHC3zK@zVB(G=41pD@~T<@Wh3aX%tDA|mjek%NaYdQ34V#uxP zO0m|-w&YcEPORHQO2X{+?4Ti34-UjyMW8D5UZbLds6j>|h$Ct>w|bV((*;qyD>VR6 zNdhHakE{*=nu_tHqQJ<&Oc5BUZYUnkDu{5Y46cQ4$*HBIBb^tAP5p{aNmj8mS5=kN z(hW3l7cpkF+Pu^uNB38_V>)I4Fq{AjrpNX)<$J+T9y$+MR{gO;gZ+LSpkxlui}o6) zN2@im-DFj7xg9i@xwRP;x>gN4*MQ13SFdacH#I~#mB^i>B*qpTvF>xlewbmz*pXdf ziGQ5r(qHXalE9K?ERGSEG0t`l@ae?-8g`uPL+1}BTW6LnI+ltE-6_Hb0>G;Gr)MY? zi9C-x#O;VdlAcjbE=rrR>&=4Qt7p3^m$3N2lxVu*;1{w7qx1w!ojJ8vs^B^x)feM~ zR1+YzTB#Xh1$M#xTxaVtz(=+35D9N$_KqQwtj8KXDiTIZlUQaCp(mOj1A2mFgU*9A zwZKl|LE7OZaSIQMk<5;;BVra^eiOJzaQmZSp#WU4IScZo1dc#~OiuBog-2C(Sxt;= z0!PDwKfip~`$msaM%`8%R0PxD4uJAhO7?LoK0Khr^U)I=ys?K=I=K8jhJv$2aW~sk z;h3KxIrw5iS_Uc=;%spQO`A{#1?D*w1>5qcs4AC|F}@NilQ~qwocfZK4sLZ$2dJyz zJhS-=M>d3}&}vIS^q@v2V5n{JSYT#$i@I(>3r~<;X--wxK$-KWWeT`ZmRzD?lPSvWYHlaXZOT12Ff9N~vtug9oz&K_ZINdV_=82{wKo-!NM)>=LZa8`>RZ**1MiYd-X4(mOQ%p5LTLC*r2st4 z6x;Io7p+*FZTPLTi&KDYBo!&LtKk3f2TBHaNdUnnNFz%ZDtc51broZ>wL}-dBBM5v zHkvW{tsWCv&NCR1rg|)XIfD04gW=vp5hO6-t2-h6FoV%MjP)D|coUp#jjW0?mR`Rr zq`CdcB)Udkd=hKu0wPIH>1Q=g!4V6ZZB1qf+Zc`tnOjg2Dji4aWXjsgnO7~OZNS~m z(2b&Zr*KITe0?B&U~a5dSK9vM+JhTBb5a_bvRv!T!ozJiHfX<0yz;oeJ{YsUAiyh> z0)OD^tbEKCl$KL+KuJfk6e|I6WT@igSQ`m6gw6whG7>2(NT6S!RFQ2;HN2#bX&Wh% zM?&QRsNQj_i;U(-INV1^HPQsGV;9H_)dI}C>M+7$acIrLw{UoUOuh@)U!lk+MBA?O zU;p`k+h}5V2$E5){?`EPJM{EOfK7*L3s|j&wg5{Q23Ybx4kg_gdAEQvn6T&?Dcbd) zAhqow&cZdgz+@bu=wOP%4M-*a{49;E|prD2l*^PH+QXwk2I*w4Zha-s|##$yZ^xcFXU-c<&q_ zQx?=>tT%3l^kIB{Exo)V<@1AXeQvB)%ch&%IR}~MN;&H)qh6?v9!Uw68LrjxkAe`J zJwZAqh>bDA=&9;ZO6-~({HgTR=Z=ohk8J%zsqzcMRV}~7bVuBEv*b7;e>{Ri1PeZJ zFnb_(2;Kd^oFRydUm^i$Ks}%r(cfJpVIEsx>v%)>#0LJsA@ zL-;r7A@otCL0SNpn*I0jZqPtOzB=~vfx7$Qd>iy&v_r+=c(4BD+3+vVhFW?(vK>C4 zUxS6Jxsh7kVH@#k&~tLj{Rnj``w`9US-t@>~sr`4H(MkhjmuVwxs$ zv~y|X)8K8DB9K z*h14;QLaRaRnXf;;6lnoiC$6XZRO_8CY5^!da6=eDm>vW`K)AHN)Wvc6;}xob3~k< zu1UiWIrl3LeGwd_b1#pad>x5PFa@aaBpgZ$lF^=5&~pBo7>s!`#8ou7m_%psBNSrd zaY;*<9hqtW3Ju{dx7{5gGj%lG{mWl=|KiTVi!@ZI;&thvTyd?~V3px)=(@EphQC-h zK_=-I2QK1v8V$Yq$ZZosgp4o9pN$Bj7%6S)Z}<%D2BzI3Zg_6wHkZ95C8I23l>5f4 zg7b+nav-MQn$nSn_3MSmK}e95$cjWl7Lwvgb|mF{$6Vmcl9QOUuQX{MH$Uw(5;C9jd?Vb0Knyu_ zx8z=axXVvQQg>hBcCB}veBXcjW@qY!!8y{_Tf%`xugqSlH}X2o!N3jRzbhq+*+v5c0z5)4&n>n(fW#L>f>OS<=||MilX9k&&wS zmCR~%yXI(=TZryxjWr-+a*ngEvmerG?fI+0)6>v+2hI^~-WdGcXzjVn&~2vPAI=wu ze~gexB9n8YLZnfs6H}{!w0Z>oHpMi1+&bcn$`|OqJUx2tp3Xfeo+0PCoT&SF9^HVc z5@m_b`nu%HGO4j5n?q(;hA3#j>@Ov=yc1rKJMuFPCBB#P}t=AU>DDV^V zcujsnW$~(UZOU+2whOFOWva#u0+2kUmyzYXviHmiep_ZMT6XCUybOf4b7*>7NY1a0 zQHE>;(c8YaDx?p!{9u;VRNma&xaPmB1>0(<1hWFQiUI294EtCm6Nfi6y{h{|h(|5Ug%zvGL`T$!)-eoC**KkF;=<>~41sta=% z&EwlSCJ5!x#9`_lFDQdAUu;Li&(7QsB@G<{(mhnP;bE?#1k-p8ZNX zyzko6sA_3{leWX;D!)%xf&Q&UEc-sY(BBf%QOE;imcfjNHfcU!Ih_oF&kg_kuSEWW z`JNwM9DbhTd;Yu$zK69^iZT(CuNfdh%mVvE57%UVh`O{^rLX`+#Mt7UD((@QD%DE3 zxgFs9=69y7A0?7i53O_zeM-`|pd?br%o5uA)+$8_Pn+r>45-BrIO%#$t1pd z23#x}ck^PpZt;YhxX+%nY4sVm(t6XPoZeQ$tgdZ+8|Td6`eKyVYaagtjOD=8e?h8w zNZU=(3X`C-LZyncr+aISy;&&))gp*kUJ`aQk&@iW9I}}lwSwaAlW&A&jIlPtr~L|Z5y9Z zhG5E`-LM1y=LJl~JFh4wW9?bL8X=)+1V5JH?amM6e9!_pGqPm`A+)|(6HTq2Fk6iQ zRcx9jh*m2>*cQCnFe5{^y)shax&l(_{hCnHqgW8CFxzMdsTPlRoX4q>!9Y^)W(8BW zzd*{-dGHIT;cSBC5cVnA^A7tyKGf-G$3Qs?1>ks*~-dOIn~$U$da zbcq{D)?}FrtNd|(`4EYH*2aGcc zzw8{GZgewF{Bsn!g$k>-$42IiAWDjxE7y&zC9f~c!v=^{ZWxBXrj_|?Uxio26#9aD zAF;NngM|I8&V{bJ3L}&;m35|F+0PXFs}G2rwiR|)I;y%;eSyH*1hrs`6LsPf@kGtL zSJoY}M02XCEE11VL#R*#*(7dbRP1&zO+k9klP=R&i^H)$8i@^B73ab=3%xGc-|EsX z8GZ*#vCl`7lGCaOv4HB$WY2G^z;e((cC1UO)Vnb!hufB;B9mrWz*aM94cWx}9U zB+w03x2DY83z!1u%tJSANlHDa14B@+oXVKdt+ME)4Letn`N^x`1BWZBez~vjPMsKmPFBG?B@P)zI zf}XQG;U_s}TwVLoPngv7t~gvpL&(EoqJZGhkx;{6J^X_>HAaz@QQ&puAF4VIuhiyT z`a75(eW^a!g`1(-GGf_WOTM5E-qrK)#l;8nL>B$ zs4u8!@Tm6f$JjiO9(oQ{>9)ANPwA#b=uzpa^`hXa^^*J-t}y$ruTWR~m%SIMqt;99 zsHHR0u5#A$Mz|bLqf0-8!je3kiDN-MwpSt4GT!8vYCENGbRpdIfy#nFxtP*t@o?;q z788H850351_P>f3C=`t9Iq0#ZJJ(OO;u!YN+1}Oh2_p802~%sX9DDld2h8pXf=00flA{VO9P}WAjqjFZuqy z3#Ve%7W(yYqxy5|>YB>O9dnRMaXlRx2$r?2Mn=C_t&LeKfJk1P)Ra@9hSP(&bjdYWzUk(;?5Tqm(kdw+ zbua(*pZ_Ozq@TuyD=uHWTJ5NZa=DW6S_@XSkbyy|O`?{{m1jyCR*G@}7mCt^;60sv z;-64j70Rt>zDt$X_%BkGkm5v7yoCtGMH_Eb?Pg=#TZs`=>+yE5KA^b%r0S>zhFI_- zLlXCvRX3B8dPLx>J!T6qzo0xvq^VX5$2}rFBE-zU z8Tzw?Qy+O(UgFKWj;U2hf5S@B3VrvvH#N{&5SMukY#=-q;7f+y5d0ywGLHk6p3_jt zNN{{<%dDe_}|^fsISNdR6k`~v~qjMfhDbT&2vbn5970lYBug8`dHY6EBp z%oCv?jcvqa>5W8RmuK---=T0onFyheS@o|vT8G*fBzTGmvM9YZB5zA8dt=FkShidL9ToR$zi@h?PmK_(dx2|u(5Z!8?oX|9OFev=o-4wHYgS!IN&p7Q)@YQY_u9w#L5vOGgt*udy>2|zKBQg3 zd!%T-LI{BaXTP23d}j(J8XOVhAXzBt4y_b)DQQ;--oJGw5jsuAP~VSY*LfXXW1q>! z>Tp09g(cj=!4fyCKMxR~=;wML&OJB+#BHdQ!U&iRyt7~ew+OzpG5NKSg6$Bh!-4X- z8BqB9Bj7~k*ey`vRC|Cz7t7K6oZg;nER^$mj_@FB`yHshV95oMBNSPLY9iR|**qXO zN+5?P{z4jOXxAerXcKUPjZ?16&P;oPIH=`9t{~RlRfWfEDq{H{57K@Hs-Jwg{ANgE z6c$I~y`jr?vXxj8E=uzqNeIvdB0?kF*E90(E~jg{#nlH z>MUf2H{+Th7T`Taj4rH$>jFuKR2Uq(i*dBdJWaOz?QJL+?qQhwEN6UP ziv4^zhc>NQh4@ThhU?+H^w9#{j~JcVq6YQ{H}wATE8OA^{OwSv0oG|U1CwtjES)=? zJ>4>F5L>&W6z#a7-^Kp<0<<4geH6sV$4nHTx~6&^6Nj!1PMu9&pr?5Jo)60pA@a04 zZ~WvsnqRiy-u`Yp&nzy`k|iqQ+Ec<~xuSt@Q*31ZByB3(O%DLwLg~1fQ)YefN>A(& z51Tqf)yJpv8X5_@{I#bUkl*Y9iRch(aLvPFg+xEkk5K+YIepG!My73>kK}4#a6O>N z778vd$AyhZK}ROOo7`wEWLb4sRb)6tC86bdhc??+i^EGLeUVs)*T5u2Mh{VOQF^KgE#^NBIXDagBW0ef0e(C z%wT|~0(t)4`05$@pSa6pCDV-ny`jTDGdKVy8P5saQ!ksleHFoB2E`w-JMloZe*}6{ zHmr~vl{GMB6IJFB6%(6)tKUUEI4io=dQ@=DviZ%Dj>gG!l7`lDKm4R=HJDasCbf1%fFJe&CdsR+ck+>uD2HCjd&C0A3$*^Jqz75 zkof1$5nN9xcif4%2Rkpkp-Ac4{Zxd%p|f=rc&U@tCg2GP7k)@}^C9ZX-ks)v0lS9o zrf~4ruB5b#@-3N2D^l1W!jymuW@c0ImD*d>&z$+VLT9(@;h5>C1$G@^c*ZX7rS>Jb zrTCfM1?s@i>D?9H+g6OzrKPP-NMtpPXfaVG=nWS}vWJ6R7iE4yt$CWyzTG{>yw zA#)?p0>NuL<6tD0lZNSe;7`cAl01WxC$KF}XGxoA+(W7wNuI8uii=Y$rhVF1UFBSR z5q%7FABxRf53E(awt#A109se_$VGqBUO@N2>ShMjgcS^Wu`o$6Q|@drw-rO{46QK8 zJOagbM{E?>R`uni0yT8fm$u3p;Dud@Y9Bjsbe>#;mtwIBqE?J^laABk*pQ#ZEP%t- z$RQ~NtFZObjQguSePE*+NGAi`$wQeCN``8&-K6b7PdTrt92{Kd$*$m#fl&+Mm41h0q$6 z=!Q)J+52zBwWJPtdR*uR+Tx?Stu5kQx{!^1p?}Q}=|)+AkkaxXSVR3t$>v0D)Z)Co zfvGY{V4Iqf0D*h&(mro1In^*4nC8ShUA9TYXKidrhb_*Nf-I3mqJ{dnWMM|x`k;U{ z^XKI|B->IWO*vWs^}RoVc^gMs#4D4!Og>KXhILw3ai3{hsB)V!KD z0D(ECRFyu1!*&E^JBd=F&(>HBbJ!`ls^I@YNwoV5yvraqgb7Z98k8tBMp50c^nkaQ zOt^J*<7tasd+B?VWQ?%=A!RtP?dXNHce>endu4UBfo+O!p=p`I*(8C9JwVU`nTQ}X zhE04LIqp(fMs_pvgV%nEj(4f}tAYp_H;`3L@SDA1EO6Ik=T)#D^#x*}`g%~upz0A@ zY!*>_t!?n86qiXDO^!i?`dAPw2l$7BE=3i_Xg-@S_>9qsqm4cDV!w^AR{t`X;n+fk zlYGq>jn0;}4J*047+nmc3o`7{gsF@5PC!McEdb0b6tyt9xH)HYO17ic+{(Z0HH87w z?#QjI^y@arR!K%2|B9?X1MY#Lwl>7d`(%J=0#;$7dKZHAWq$?sR!B8(y+!Ut1G^BE zYNj6uA%IS8ZQ~2}OV|28@lscIq@pcpDV=$Ki)0PKFty=AB7!Ee0Yx842ed=54lg9? zWj)L;?Xm@41Hw=qitP)jh3U@A%#slF`L`hW(8dszfTk^mLpAWs87`o}ovKX#&N&hm zNpc5rUukh$lFp6&7MVYdZ^PjjRf$a@0gZkuDG8~_s3R%*mFs9ds4wlh1@zg`jbJXa zHU8R7oinfx99|FoZWb1-2GcVUAwH$qMa*vKtD!5_Ss8~4nOm%PYbI|&3S~#-HL}lB z1>v*CCI87_q;n!Qwcl;Zk;s}5^hKE|3B^=uB7E1E>`lK(&mlh7JU_SrQ*l}n#KmVN z2CGamH?NIo0cE@mk^1_zKH(d~I4g%;0pqN9YhoOypTROeQ@>p1@AStfJ9Z_F$&2e9%Bl&VO8WQDw?WRlC4u-(v{J<@)zEj|q z3EoZ@r{PLLEuMf0lnAUJB2QT8M}a5uWP~{5A$BFafZz`?2cC`oxwn`kJ?FD8+c=q= zMx+qf%(f)dS7BS8ZAf#qY+v#tf0BLSNmv{5`O~Luc0_^z>O>@_$deL+HHsN61Fs*# zp_+2@G){&F3pR);OqqH5!FW!Ahs06iekGENMDZ#=yj-~c4QeaF%VpzNZb@d<0tqeo zW=$IUg7UfI0CPT9am=xZU=@2`GLJQOxuiFcwf6f9ou+C`F)C0Du-zi1Un;5!6pREZ zcwjRKVzS?eiWq^Y6Oc71IaxcScRI@?EEQ6Z;f!aS)t2kMO4jersE3W(uuDb(lzE&M zXNYbLqub(M=)~|K8ekjaMy))pg(G3TTk|ONO{&+Xd_)8CXa-s1#8`{YpOhldmtrb( z^2m%vk_M7BlCxC7NCY7?XS}pVci}ughvPQ2M+N|D-<&PC`on69Jqmg@U6{mVTEuMm zA+#pps!&vQ{5F*q&>Df3spiMmSHrcvCT(S_m06tWCJI9%1x9vN!bP`P(|i9czoO-s zckQ38i)!e?;8t-DT54;QMdcl=&;@E`y<3x7q1>)Y37%S(?Hi}c|J9lRQlRKAQfqn9 zm1pzb*P5vl0Cmb{!Mj5DEyeko4>se~qkS;=Unrq#h4iY3kh4XSK;4{@L`nV(4`>8h zz~j3cg}u8W0#z@2i5rFe#TgDN>88c2R({*pBOx7Lf9(G0SvOovCgy*(x4-_mP&(n2 z3VJi;6TaR1IW3>?oi3m7eRTGBDrvN;d;-@!(xnT!*a;Lv;)VyT8}GoI_)fkt&M0Y? zanR}5wR@n9?z)4j@68u7#Ca+!0S}L9>OsEgJbU_dcGKx~K6^(0k_978ubv4LFg+!d?|l2to&wy9 zW*+$Ft;G#GP3YwkZXvpI=DIl<1 zB(ui3`ra;*i-AE5g0!4Zkg4nB1JQf{1s->{QD$AkO&4IZ#xXZm1A*j~O24v^ z73-WP54~bNPOBA5)C4(I;TksP!CIS(a`LG8@i5DizFRHnl;YT?(Zw7==*<_!X2rDi z!z?a4Myo}F4@9t9JkI4@Z@7ct?2tVq9zV=7b?>bfn5u9s?P^m5O*L0q$p+2U!z{II zq*lu|$%C6N*5uB8m?fJ2&B8V&3>b!|a0!}MYhHvWrikUkDK5-x*U(#N)*px5RhfyR zxy$qayD+Tlsr@ppjORqfN7jueML)H>94#m?dfWz=DS6jY{m|NoY{8EFTdD0vQMm?K z^|*rK*~PAiS|C-QcBHjcesdUt{7hymT9^YbHg;oEzN1uknv;d4HplGXOSMz4lwMjX zOB$6}wScbF+d9SAW5Yf-e9JA+I(iKY7~NtY?m;7n2#vip35DeVw8mo9{IP*ah^%Mc z-1KAPvN3oPNXf!!!~r(@z}6`vrN*9RsQW221V0uu1Q3dtk{S)c4|_kR8iK!T4Z-UO z#SEdIf>ZyDtXaK@2&+mkoV#b+TOT^Wt{CaNlr{h+nH%^WPq=CNY=S(76Z4B-(p^u{ z4C!OY*k1Yr+|xLUF5k^{Gg31QWhj}KEh1wFNXBFtSbZct-FL0&RJE`^(XDvGRo`2y zfnFiAn93%ZuhLO6Pk;0#ixLfotSUQ<__ln*>n(eO{O~hV#mz*secylk2D%Y)8bk%9 zEz&vkK77nCLb*JZtmV?pj;6l6C;f<5@;y(`?CYmip*G1@{uFXyn_gG} z^k@a|vb&I*g(zqOs9~020jx2x&lvEvsE$N&)=+B|u-592trYv7m15KV=Xs^r-yc#b zmfhllT#$Xerfi@|vBj%anFg}sGRf*r;l&fcX3*la?^pDDs*EST~U-LYK$YM z9!}Pp_1c)cIJED<0%~O5u8A2Sf^@kf;(=I!rh?;Zy7p@zRc6L6U$4qavJ#P$R-G_N z^#TOq9t43Zl5{bO^*X(gf3`qDXqB@|emXnsug$M^D6=Xhn^KB(VuV-6Gw9x_$ern& zOWsM}^d}`iLsSB}lX&5+gWxstoT}eB@+-i`q-RdQ)WqpeHZ(Np4Uq&$jgxlAKUIJH zH!r-1z$*?2anigQ~QvoU;;l>K%X1< z&IJ*(53_y87COl-M;3G4+1ukSe9lhZ)QT6YLb6AXH?p-5F9Cv61T z7mO3ud0{=Yu_FpvC2sb(2qrbRa+~8KJ+zcKrLo>O@}FX-PgpxCb3k-~kWNkiG_Yjf zmdf-;;3vsGW&xw>M#@5im`!TfG{9gjdZP!eMRK4JX>`u1LIZ5@gP<9Cpkzgj#vxDI zrh`~$-)JmdV7gf&XzCg@m^B0$r@n{Yz@r?UO^Bz~-B8wzMh#7lgaKC6S77Qpt!nV750(T3bA!mA~~)da?yidLO4R1(Sh8z zq?2p9d8Cy)Tb!RaFz)3@B$Q*)!A8|`<~||qo0?&BA;ct*O%U%f?SHFg91QXT=im&kyX1e5$QtneH9!4>MCw7A(0qDh1#FQsIH?$RBUSR&7ejL6cd?>m~^ z>miR;-xyQSaAX;4=?)xr#_zf@^#RYV8HT1rNG*t&^OZbL-PMQ`&>UASiqor41BSO= z$cWSQAV@GU1wl<9lvnkW;s2<6xe4CYz^zE+T6+Fk)`o)W#(KA=;^y$CudOgm@0!;& zwKmpdTkCB6n?Y(V`j_J7x1+du4SgT6S*$s6omYv@Rnv^SrW-<-q^5V>i<-I+8wo`f zv69$itQExH8>nfYwz?pc;n{*? zl~KaJAA}(1ZwCRZs1|D~QghT_5qi3jSJD2)nsAtXvC1NkQgyjd$PO2-tltEOsA&_F ztR*X@QhH}^_7#>$g-J4hWsO`9k7WK9ce^nO(fA-01Vr;{P5BV@|DfOm$JN5D|6Y9a zIH#1sy$TzGnQ_~MOsa>$Vvf{;mU9S;6h)vb%ZCmw6Web-wv3;y3BtN^vdB=(hP62K zYW~)`R~`0$`82R2Wv3_9V$(hi4+vu8GA*^)2l*njGT%W!Bw%0JyBT z0opf}Z=^1Dqg(EA%+_s<>WwY_jky9U4gZINCCUx$Vuk)bOin7*o~ zg*f_=H-nn$t<=^oX>;jjKl#)y>EN+J>Bi9r+n524nfo6kx4?g}8};$+MITB%JGa0; zHsMB{^Nt%uTZKLFzBAN@wOt6?az_5r3uJ9G}tW2sKL@BkjkiPtUQFMW-=G(-hvg&YgcMpyx@idva9^CVwI*Q?pF7Yi*4ZQE*c&U6| z>%j`zI&QGJgQa^kXp+53m-^5idvSan&FyTr%lCSw8fg#S)#*v~-BzS_9~tCp1BObzYz_sfx8E{oj#1sN zHfX36-sV6SN~`@zLH>2;oc`Lxqz`2~MJefmErax1*(b$qcB zA{!i%vGqDskYx(vbysq#rIjT!Qh%4i7RdYAh@1$gOx(;zdq|<@-@y7A#|T=(Ks+&} zH^6M0lK&Gyate;x7Xy61xdW*> zY`pv<*!AZK3ixlk{9tmi2>)oSZ@}t3M@i+NM)4U%qelGs=I~bfYk{`GCAUKENXol3Y^-&iW zG&k5B^6DNNqwoII`vqBy5Buxw-wCP-7ZdIpMp(zfr+guOzPaU7U@nGdZ|8=r-#+Wi znz1_EWW(G}+Gnd({61+X>VB?=cE4LDwU2mJKY8sT;UuL(Z*3yz`*S$8IWM+oy<6&1#8?c%r^K#Cnt^MgpeIZKB<)*~fA&Kx}Q6 z$@PI8GAgSm{71nV<4A05sWV2B?EOdTjo~M$I|dXX-tj!Txm}efkrP7kmzMiQ5R%u9 zQlp&S&ivRYVNySb{rTLxMR@}LcZ>ZfOlK~FoNsOiaBM{d1MW?il^#&tiFo^)4kG6h zD27lBendlXH!yos&4c>=+;_)GGAo(gl76VgufN{G2xP`t-GhLK3Pt?<66MKZWTO9Tk_p~*8<_gZdPtVt9F;OH&#rp8fusB@+Q9} zrxp}C(i?5frAL$uDZDETD}#oaK{Ity;Ht%? zNnHKM2md4Hq9+oViDW%gLausp-_1PD4PRBikZZUxaVG=5sPef(vQqJiAP$*!>~K#Mo{ZdibAL+7 z<9G;)>!3hVosUsPY|-W1JkQRz9uoXe*=*y(P^GX=cg#IQBMMY#&PHWnr27%ZsS%JU z3YnVI+zBAUharm%nY(uuvq^+I6&dg0LgYHI!XpEY6u`WV7D%rnMNJvP3`+qleH}Yj zfrlWs2q2z2W2k6$51zlF43}_1t#A#i_3=Q4vxz=8ge1W^eKhx+b@c7F zwTXNzt1XA6Tgf@9u#|yxx%=$t7ytg{zkRiiVX?T;s?)zL-|*a2T5L9#dQ>|tp4>>> zz>t!FNkkOj2%-EO!~jaY30KdVKcoUdBlTem`bZoTFlj`HA&D=y;!W%d^*PXeZgxLb z??Yzr7CUhY*h)2R;tl2Or3@q;0+`x$U33OsnzT&aV=xydc#-A|Zb0c?vGhk=Ecxh(a8;;kQ3TyQO)C>j8M@l_ONe`3z5A!9I(X}Jj-ZG#!e7zwnQr)k{FWQEEEkq_ zZ#v<#B|a74UA&yi=h(UQ{Tc4x`99LxCTZ$jq_9AKsF5PsAjy1fqtLUV-zkn1-7fz0 zl(m1wJtZgM72MT(N_$n9f$`0L!0 zybsWYF&dcLdnqco&M75So_e=*4+CY0tCM@((O?Jp(L;>5uwhCmsAL=|-xL}5Q3sF$ z0lLnA{pbJPhEFhMJYaU4N^H5aglHZx}_DL+d~0JM~mdvCN@g)^tgNEMB< z&Z~`G%`(>)@Au{RNj1?^F$fj2dMk{s5iK7eCZTxxRx#lxvgyuPRB{&kRRwhBagT|2 zx3yS6o`LFP^HHQtx5%1Iqstz^LUC6r@k@nfgWa@2;(hf}ZJGfh z#Z(eZxCUl(>6DoCritBNM8tfgT)Mr5*8wWk=C9wxB?Yc~&dm__DZ)=}?!Z=sQ83dI znTN)K=#v{swj@VXR^cfr3+g z*)2Ko^R3FuBRQ>>vg)x7WFAVD%e~|d2BZzz>l_)uI<=Ao$sWFhqcEJGseGX^lc{|E ztKySYHUiwz=K%_HbmqZu%mb+>U@Y$_H2@dS*75jTsi{mU)aAW2fgwrvVN}!E2I&X7 zg)RkNZ1Aso%P7@F9>r4pR!9N z)k+L?h3T4UNVOxHJf0e zqbJ3^&$6jYkIbtJ`RxGc^q4Va@dWsrhjZork=fhQk2oQM)GCGv-g@}QqkEPQO0tl*exde&k(%;pKU zJo>p%!}7Li?OhF?;Y73Yu3D?R0hXcI>D%v)+wvbJogGfkVD>C3>!He6!GGxEPn|j} z2C366IT@N|VmUp1?T~9yQw&Lx$$%V#(C)F%w>9*-nBrpj?*4V$$7%LQs4J~Eq{w|_ zZ=na0v}xE%chs;<+7_YK)a;%ld-zVv+H)gopSolX4b(E|VbR{2zX zfY-rn;thRp3)A^ITct=>NZfDdBRnxxt3Ip%b}PhZQVxU@|0h%Qk*kWxG?S#ScEXBx~As8+ht{M6RJOUK{Y)(?LjES{gm` zkt~E;DiAMeme~YuqxN7)o6Ih8o7^TXX`B1fnyc*QlBV`{^Qd~am$k_t1h>lJ!;;3i zFRi&|&e4({GT-U;vj}L2_;Yk@>p6V8kLlA}^&vS<^I1lwC(vy8vRW$vw zUN!oRYpLC2HKZcyX*SMz}WRaJo~r}x^M?CXQnw>6;ayeuG1kOa+t9}90svE z2XqY>x`eA2i4|$q8PHZwJ+s>znZ0sXHr44*1oP#vK>p|ZuDGhiJL~bvXi5WizTrEK zNG6taBB))xlH5_+$Xb@{1RTlLPF%{ZhmBBEpiMw_Er&=UMjOW*wdo9CX`9XOpg6aaKrYvP_2zRPWrJfa}x z=O>XGL;K^Y!Cu|FFTG3BtVQflZ1aZ3mS!GV?Q);+YM-bOs*hxIdf)V36~j zu{fW%gHp7VAbT0I4A>QM`aDEH8GMABr-X9_nOuzT!0pn7TIH-SI99o6j%7F7V&7^= zx}t&LWfqw#(6t zYIj&B?;p#Mh8ruo1c&3S*qV}q3K-1w!Z*t~nhv%#T%n)ZLoqI2SJ(KDpIz_RU$uCZic@ELqWf z&f@s8xMj4}beksd8#`c@0}V%B)jWBp#RTn1uFtDQNXx~h#oG=zwCHSA)_lrp>mWf2 z2R>j?Qlwv+<4aB^>oL0_e1wRN9II~H9DQ{X@LYvg;Z-h=wuTIQwLo4&%9A5mJQiCM za(`jNbBe%|$e^JEV}f@*95Be}iV4g!oXE3i2#FRg#zBlLcj+J^j1-p;JdfEaH?%!TSkJpEiwDUOl+<~T z{y?OG!sP2@Q3+Y62)QOd@b$JSekhN&34WMxhTucfmA-WZu*Hgyoih0os_j=9G%43j zQLmN@iWP-bg+mFhC;`l>(u8x5#xpe=ATb1jH?#xW&<;rVnXKII;<(ydp`Rl4`*HadIIjj{jTO5F9pG?+ zm}edp1&StscY+~q*z*=BML;rs9X}U#uPhUZw5T{Yhpihuk_ipPnYqx9c-^J!5sP}q z`0M@$nRkQyI=-5Lz7Zlx`cX|vXai@78uX^ZhD0&i(ls@*SiO)ey!>qDGq_0Uhv{e_ zm>DNPaYMol)BQ#GKxOlI`B0Cfka-382AGMSo;{N4(GwY^kan{CkO3TnM7}bhi%sYR z5=lL-4j~(*45K>i0TrF&)W0w7*J#YHhycX+$KEW87a6J}M(KEpJ1NBAC`nVgaYAM) zktKvMx8MWB=65)1NCP-dn$!w_GFD z?h#nfLu75Ns%rKr#RK)BD1nVB9I@Prxb0nCX{Zjpm{I{ibt6ebmfkNiZ)o9(h;xIr zr?l{Ti;rh$dHl{{EQT4>T!gGdD<)(skmcJ_8KjmhMKhDxV`9zHF^ee<^~%R0SFE6K z$2A75V;%LYbWIVVQL|?;VU7e*VNP&KfQT(L_{0NjY3NEBUbn8y!gzm%q*R@d(r;#r>dS#I>TR6K-55;ug_zVwbYJ299!xqhw1 zGLrk(2ga;1+^R}}BG54WGurJ^QW10mt3B)mIOIqgfb)n)yAP@m5pcc0H25{0rd>=? zW^q2Jihjw^dxpAI)Sr9<{~0Pvu){9UI|du@&O{H?PS&KuZE=gUbMJ)J2#it>a+t!o z*9VIe+z8N%8Y(6FyJSzPNe9v=mWM@9FpEx$tg4?5$0;zvDWQ34fo4nuvCaRow;fX$9xJv=S9q(QT;NAJDD6lm?2??m6KCX@-UkQ;&yHE@B=D~nBNzhca^Eivj5Ch{PS&> zO!w6sb*P&h_b_q8%cIvHv2cAM&spe*)gh6adpiE4w-MNbL5=gv=gA}+-O#Q)xjIVr zH`McJAnyqW4YLfTDo4pM80M&vrs~Sei^S>N1>deZ(8j9C zv%>x|fm}ASDD2E1Ctx<5L~LQ!5Y`3bisX1Vj^8#;9)?eJ&hvNAp1*z#a`2;tJL6%n zyEE3z<@Kx4vrUAfWR5BHEIn<$ZmFXW&XX{XK6=kdPv!R7g?YWkPM*RPhVXA|<_ z@7X%{i1AL2C8W^C)K8&>ZB4x9W=)r!77_H9ElF@h3erQFtvTW|%aN#$%vH$hW{n)I z5V6c9d%r`Mtdu9x4iJ_aza1Htn)$vZ3Q2!yRhXr7RgQ62_qI%mE~TC+#A!>*zU#%4 z+Jm!H5`h5ULTrOr-ww>}?Etg%iw(gne}qPILoiVrf;Y&8 zXNB*XW23&f0Oifgwwk$*tlMM}=j@57e*7jxlKun^DB9i|N2hfQR__m&9Jh0XqxbP*I`!#~4>+V+3F0C@uYmE3FB~_9H3ee#FMnAHXvAAN z+%>Sijf1-a?Y#op`TVg!E}hRoJ&Dz*KA)p%gP^?Vz(sCHGbf#GXj-AnF|3=ij)po( zEwI|s(lK6hzzXW=>|B`H=006-!&g0RKC+CLEWzevC4$Q@+0xD(q&6G4h%8%>kjWpn zp|9+T1LH)X*+iqMe8He-Nlw{Ub2u~-hEtx3M{Y)360;IDQu#5JPNATX4VY%0B&aER8T5^jeT0MwAFXjDfh1xFWjDu%2j zRME^qDG5+Vlq$w*3Q|FDjU zqiRS++86>_nUoK!n1+-rLf^{O=R$F*i4)l+5LzL;G@cvvrA9gtOjz0yqBKx5Xv)Nq zOK>%&XG0gut&%oHlWN*12-=gT7_J5xMI(ze5|mCTQ;gFLn1V8Qr{EILwk&plg}KPQ zvbdHt+r5cScLqt!H;Lp!7I~%dBZSq0DRV0aKi!B8TJC2+`-j_+e2}psBp+^FrIuo( znPKqbX#|J+zz=tCLtIIP%XxMNYFEVH6~j)AVc+Y+&`2~K1HhMWI7IB(hf#y}1iyg! zgA3?sHPDMBY^ohR1#^^loDGObm! z9MrZ;yIM?-dB`BXk>|-|fHTQD$DPTR(M2oE$PDK)q?uFoO(ChsJIT9e;eC=rej%mc z%5#kE&LUUIH_quX@w3A8?w6*=#aFxO@jh0Y9-oynk^)(~$8%2i;FrshS4m+Ec`mO$ z8?`29T$NJP)A@A?v!jHs?!}W*Ondf0k=CFXpOQ156iGZZD|kXtqefmbb%---lj!sm z*SF$=K-L0Bhm#aXFi5*lo+1vs;m8IZjWeIXFhxq3DDF}UP?@YHjT*W{P+uz)_1Z)I zNxD}fU^Ek^y4aSNZaK+o5?YRaI18=EHMfkFJ_3Q!jP&4$Sud$x2LK{ z>Qa_hOr2{7)5xj@$e8+PZfiLa;+Wtau)G`uQR{DO23QSH8(gvui^K*@Q*JQM?Dxue z>cK{<8Eu2hyAL$kD!5j`a3XYR#@VRV2)#ibblNnvz}*2Z)KS%;!G~$PG^|uJ{h-R` z#LvMPbfT)Y0_wpud?O?4bOe(VY%v1AzuQ(6hBjp5GjsHB`$-sD>Y^k5UJF=R-t z!XQ-b{Q<(lps#j8)>!0;vyes}ZP?fhU2|RGg-4Bwesraf7A6~lD7F69u~gk7ecY*shn z&)jh*r>HQ|dg=9(HfJ7>PzK5N%sPoU$s5wp>{7$ZF%)rXZ93UnK%}WODA&?Ug}@#x zx~iczw16GvTnVC8Fk`FK4I6XSuy2UdoMuWjR9odWjj|i!wyv>b^V{cO!bx^ef~vI^ z>CJ$%eRLdnxhGMQu`3Tzr4H1sX-2tCmX#q$>Y1^io;tUB;_xe;LO|c{^?Gp)*ro@yomG6{v>dkJmM%vKQ z?Gi1v65Wc?CQ+#obVEE=W0g37+9H?fsOd1YYDq>Md*la32Hm2@=CsbWNe>=33q7qB zM-S%OfhZ}2d!{Ag&m5ulud$QAg-qNwsp+P3+sn(lR23=ys=C9Ae z7%QQswT9@y6cguGJ-rkwGt1(Mw9CYSP*xAptobUp*In6Y)g$#_uc>pcb`jbN<83K; z27x;`>acXcF118GKIEd-Exe`R8Tk0jt-U(*IOcf=oO9LWQR{YVX5ezzx>VeCw5#>r zRf4JMQt0!_W_{X?%Lm=ObZ{7ym0+%iLfa77u%X#xKAY!Vr>)fl)H}z$8e43he>Z_f zn}a_GQ&#Yjt7L!Ut2`^qadlzW_H;8F%7%ULzqrpX7byPN-Tm>@zJ@`oLzfk|F!0WO+yPZZAJqEK zKW}hB6z{+OOO6WJRwA+f8`;YI)}m#7CsuQ_H-psmJsC~SUWoej9~b-~ad7yc{tL-I zpi3~mh{NlHB$;O78g0j?7ehz8TVLY~z}yq}Rj`PQRY&hpW3>XPy2;gla_i6dY84rN zbv-#-Zu>Sx{W`+4Feh3+L)pcG&gK<=4pI+Kqj<98C>I&>>#YPf+Ia zMXg+SOJ$-2yVMXJ1VWzcYm?Unx2LatRIwWT!ND|4lUXo)E41UF&>YZqt_3;RC&2@=E6ehVT*ftj~JV|h-}lpcJs;= zcBb7WsIE3I6*?7wpEA2I`}0rOtesu~w|t^v=(XngGKw$QrQP~WuOcj+qDn5iat?JH z#Y|z0UL2Dl%xN@cx2+bdQLi<;9Cp=NgnSznB=&3oLyADNT+ngJgSX&d_q1eRvCT_X7g$I-?7L3;~rB8kr;TO#ExkE zWQx>@(SUCEEMOo@HXD8OO%$V1JPwEXbn?wCoJ7Gl<0OqI$=PropZ!FjJklPpikOb8 zB5Qf_=Kz)X-@bXNkxEuAa`WT~J~+mFJ6KGzt2M}U1WeQC1UeA`+gWIS(1&V+?uk`8 z@xaC5&_fm4)5X-gBGO(b3-2mGp=f->R1qT@LoREbd6yAx{fraPGWE`rESH5w;aNGp z+!=VBinT~RpxqIoF0&*DSyj#LtbPq}&B(v%Vj1ZDt%2efr-ZDpQm}LeQwq4{pa~8S zQ{P-49Ge`IY52ziW>V%63x~mk7DoyOPRX`IUqC)?f)ItbO~g8#Co#~tN^w_C0BlcX z^{!Puej@<&lGr;9qUj=CnTQxUqZ^yqgpZT>SoE`;tiU31a$!hP1$;{lanjN#Frpme ztU+!$>x?ak@if9_UWzwd?l+axrv(==QJ02aVa3JQ-rtXo4!kf;lQbJjS@#&v*&}bV zNQvYp$>f?=9L_1y$E%8%)9&M{=M)1{rkWE;Dg2Iqx-mj zJ|5lkGkA4IgK3bSkwiy%k()YYW|LcV`fp3gPCFwFnl(uNlJYDCz4=z$6Ntk41X)n9 z4}vVh1=Qj6nz2PT5697I1Um7CYtjV#G$FoVm*06iSzDq|f5)=FZpqPz4956t5Q4N> zp5$0$w4LP(Q0;kX383nAas{k|E(~|4*i*4)N+f4FUd+~@2j4K##+!UG+HK8LL2e_kXg)iM(YuVdN zI6_GYYWrjhAfiS zE}Ov|bAnwQ>2Cr(8TU=ia|hfb55{sZKA#amv^ikCl7bZGkp2dPmFT!W{-w_KJVpuB zLu8CVyO9RWF!YY#{PAYNHOYK14cW?E!^70$3H-7BgFO|`bbyCNP@z)rCW%^;`}cG{|a zqWP@#J^6;EAGmwElMgEZd(91BUpZgltQCG%F4dLry9lqbo|wtwi~SxKocWOb?MrKj z{SC1JNqV2{G3{l@yRNRr`G#)_ymM%4gi;#dT{s6c6AavQEWYpFD`FdCOZAfm&q{h9 zxLPhC$q1IS)nx~S6_b{*7bGs7TdCUhKt?-d1S)ykU|;(@Av;8w>pBH1wzlNT7@o4v zkWb3@Lyeb;?#N%h4Wgm28!8RPsZx?G%Q%&y9s1p8zUdG$<5KW-x<*eY#OBU zXw^G{Exj#uP0a#p^{N!$WdKhL7ZI?;0W^i(UBRR_F;?93gA!?YIufyR8I`SYHp|x? zIi0g1i?*-2a-K3zK$2ebo5>0%l`aNr9dB|T!eg3oo@1Y^kPET+X&Ju^VL3@1;J55YnAonO*s$Ae##0z?1$=l^6LuA{#o z6G8Pu(vH}qV^-k~c#%g@!7oOemP{jpzl`Q`)MD#WWo>Yb8E_2YPS|`HV8~$@O3?iQ zfnkUuXY9H+VblXlSm_uQY+Iim@j(5r zAsdeH8Ljj*WH*7TiIOZp>R5b{4LvxS!`VE)_8afMZm{2&B(qy&V8LOLl{SsctH`%8 z%3;{C5IKBM!6JtbTJpr<0}tDa)97qf?eg8jTUKo6NB*T?GYm_T{nsvNK$i`dtqx5-O6D%5Z!Zb-~yiGXwO-S=mN>?H(QWm*JnPwF?;Br}RaKkhA`p!QNBCHleICY5Ukt z+UD$1q-&q#kI+h{YoDof?RVkH!6HLO3dx8CGWtd$Ay6bqrNfimo%e&wU>;4LhPXa^ znsMbkz`8;%U-7uuekm^-%Z$_8@K5hjQm2tdQ%oUe*@QPdwU4JKevWx>*F5j->py}6 z__g%Bx3f<2-o&z%o(P@PmL$|)wv>g3i<95U6;*5^D@1}m<}l-5tu7W=FUJ$k{jl>y zN2{yl!DGZ1kj$1ayPxfc$*2h?h?yfYMuA{>1;+5L2jd*Of}FVpPLM*vBN0%MA$35p zP!?$N=1>R;tRe9nE>U<(GoME(aJjvQJ}HAI@Xpc%ktF_kM(J9xs1V)=L>Gu;2bWO& zFanbFEQq5|ERf;TP&htxiBTyTjKPdHY}YYCC>8)j$wUkYV}K^Ii1ori6%VEyHJnjY!MQ7{dL7PegMD(O+E0yfEtz?DrEVS$s=v7jr zVDmW7MmOa7x{UH`udf`)uVD!mGpc|KXPq`laO{Ow?2??AOhlc zFKojwl%xDK$dma1`9|R>(+aa>fjo|h{+U~qKgVX~T%M93&h@Xj%KYu&?B|loeA0=^ zbU69tk%v7d`EedCrKAGvcFyk){PzeaTq1zLVhUg82$+=*NDNp=!4jN6AJXFFb?*cG z+*A1lh+1mcE#wAk6d=t|eJ8`9#>mi4lC2re2v+%Q58@1R4Cbl}qCI5&F6|x5r0CXI zGp#!o%T4b-*&`<$<+8T{8d~=pt~QBE{;N%gV=fL(2W`4NV^UMWDu1@=k_BBQ@%fK7-N}r11!M7`O}D=bouInKgFR#@ zBQ>lQ?@yV6QN7BaZ9pX}mme=-f>8c!)uqyT3R0G(y~pw@+F<~vAeaW#dX^7bft;Qe zJ<`A1bcUTk$WmRgWl+7+L&!fQz_O=p`seXF)wBHBrpqhgoRBLEzoA~>t!RY^wnb5J zieCh#{NFGE2Y>zc;r9=|gMXNvlgBB@E87sn5zp`=Hv>c1FQ>s`nmNU2yTbss*7c|Ixz61i z_qPWhfB4?`HoSLmzu~w?iwO)NZQQfxuU|L(_V+*bzcs!+fB32Ce2-qgxG=x{?LXf& z9Cwjjy)wQfK&)?X{pqXuf%Vvp!nY>}-xyua9zSjR?H@10$L6<(zkY9xd+Y!4?C{8X z>;~t%S8tDuE@=$wTO8{ICLE8iz90W$J$8?D@Q;^RZyNot&c@f)x3~VsAKv_CKfe92 H`{Vxs%4Gr5 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-5eaf.5b76e416.js b/priv/static/adminfe/static/js/chunk-5eaf.5b76e416.js deleted file mode 100644 index 56f1b68918b04934facf5479be17d99789fc5094..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23071 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 AP5=M^ diff --git a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js b/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js new file mode 100644 index 0000000000000000000000000000000000000000..4442e3e24434fcd4dfdca3509b2c5e3265f17337 GIT binary patch literal 408401 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 E0a8kynE(I) literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-e547.d57d1b91.js b/priv/static/adminfe/static/js/chunk-e547.d57d1b91.js new file mode 100644 index 0000000000000000000000000000000000000000..7881644665102d20320e44418acb609c9495dc7a GIT binary patch literal 23125 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�ArFONGCxcG-CwSyO-YMNmMR4qQIu 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%0A_e8Q(wGaFjS$%I{AGwjyM!4FCs3hAARZLQ) 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 KLjfbqH2(+59DBt8 literal 0 HcmV?d00001 diff --git a/priv/static/adminfe/static/js/chunk-elementUI.1fa5434b.js b/priv/static/adminfe/static/js/chunk-elementUI.1fa5434b.js deleted file mode 100644 index 8f6f193b7e6e504664018160ec9978330525ae62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 562077 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

3WsV)CJ!G$VER$o*K86W4-C!n{1O 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 diff --git a/priv/static/adminfe/static/js/runtime.f40c8ec4.js b/priv/static/adminfe/static/js/runtime.f40c8ec4.js new file mode 100644 index 0000000000000000000000000000000000000000..12796dafa7567500f749989fab6e32f1dca88f52 GIT binary patch literal 3608 zcmai1+iv4H68#m24}u6YY{~aa6OGwMzYKPF2IzV77z3IrMe0^aFGWozW9#3ysH@YR z^Z-FjQoK|h);U$YODnBhZgdFr(zho%)YvmN{8QSAWfhY`AEF~m@h3jA9DimM8MT-AuvqKgH8JfB;`{QZJ%Pdb_NJF}} z;3}&prm=v_^SO8q4a=|B1KNR8>cL;^4DJHcXrF#>`aLzeG<l#QW;K z>*rN|o(C)y4!zw+cS5K`iWr1AJ*KtAmf_{O$Q6Y8{+`8@fsmo(C9Xhla7t@3)D7_B zQsW^PTWOa+!Y-Bbv~Z@RPjY&pW>w)=C^2)?MX)4#ZnOu4??5Ll3<)lex6#4(8Q?f5wznE z;64@Lo8`Zrf0GaYm5&gTBG+FDWd=!R-m9KGW+YEoAZ^T%`t?6KXY*6#a9tvuyw5D8 zgkG=3Hy_*aJw`t%-E#qD2H=PgqTm(^`64w$Hpn;?_%+aW9*KIQYxGYc3<>Mi)jV zLgPoH!CGTSdZJ9U@}h%4b0;kVJ+^ph)%9B8MS6~W@=HVVZ`>@`50j6dKTjIYPRJCd zWRl9ffQ0|9Lo&5fLJ=c{2L7*t5|su;R?!+w@Yf?M_79PfflLTRA@o`eI{BF8MG|JT zrrc$qN1oD)*AEfZly;(~u@ZPk2T%j zY#?lVkiiT%IPuN>l*;C3=Yxc+OxhBhAeBq+H-x3!>$j<#h-VR#T&o~RInKBVZ*8;! z(tM=2054&@Fx1m7OgzW%?xoAsyD#NCGJQ*HD79WKRlG&*dm+{&S+0}#w2g=HR<+42+NfkRTMgr#My=DWny=TR z26h@1FBft-UyqvBY1Cr5NwY`I#jdX4&0k{a_8%Fd|v zsP!W`2F6rH!Bhd#{?^`En7m)AHXkGf=N$4hyx=(7FlfKTV!YBFylu+F|7N&JAeLiwQ5@?j7lZ zm9SPCc4>_yj%Tp&u|23s511Kg?FsyXyXjETbh(!MT2AA3l0OQ-{|Z$?@?^XfEWdmf zmfVEcM5*t}!vxY?Lthm7Z|njZ6OEOp0(Mx8po;CBH&yZ*u|w{VO1G;MawoitCY^kK zemogW4DBy><})T5{eW322;MsJ`?(CSzo-zh|CppIfYg+|wV3?z2bA5ke%T!=m^atG zaK9^wl9y$~J-Sa~61+TllZUG=(!pT;~%6f&b&jGW!fKiqZ2+1dn-Et z&p&*t_yvBCvmjp3&CANzW!5}Rl+mRrfH$ex3lp^DOvMvIV4nCBoX%2x{kb&y{Mwj* z#o$9MZ67xcZmH*|e{EsfPw`9HJT%&>#os@^*YK&9_LYl&s$o*ar&=p;naKD4RTSd$ GX#aoH_pH(Y literal 0 HcmV?d00001 From f46cd7e9c750b9c4c36f0a6c4b3a1ffd2f94a6d0 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 02:15:21 +0000 Subject: [PATCH 126/202] config: remove legacy activitypub accept_blocks setting Anyone who is interested in dropping blocks can write their own MRF policy at this point. This setting predated the MRF framework. Disabling the side effect (unsubscription) is still a config option per policy. --- CHANGELOG.md | 1 + config/config.exs | 1 - docs/config.md | 1 - lib/pleroma/web/activity_pub/transmogrifier.ex | 6 ++---- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3338a5b8..b4229bd50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed - Emoji: Remove longfox emojis. - Remove `Reply-To` header from report emails for admins. +- ActivityPub: The `accept_blocks` configuration setting. ## [1.0.1] - 2019-07-14 ### Security diff --git a/config/config.exs b/config/config.exs index d2325edbc..bf4970314 100644 --- a/config/config.exs +++ b/config/config.exs @@ -302,7 +302,6 @@ default_mascot: :pleroma_fox_tan config :pleroma, :activitypub, - accept_blocks: true, unfollow_blocked: true, outgoing_blocks: true, follow_handshake_timeout: 500, diff --git a/docs/config.md b/docs/config.md index 55311b76d..d0247ef9c 100644 --- a/docs/config.md +++ b/docs/config.md @@ -329,7 +329,6 @@ config :pleroma, Pleroma.Web.Endpoint, This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020` ## :activitypub -* ``accept_blocks``: Whether to accept incoming block activities from other instances * ``unfollow_blocked``: Whether blocks result in people getting unfollowed * ``outgoing_blocks``: Whether to federate blocks to other instances * ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 0aee9369f..0fcc81bf3 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -701,8 +701,7 @@ def handle_incoming( } = _data, _options ) do - with true <- Pleroma.Config.get([:activitypub, :accept_blocks]), - %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked), + with %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked), {:ok, %User{} = blocker} <- User.get_or_fetch_by_ap_id(blocker), {:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do User.unblock(blocker, blocked) @@ -716,8 +715,7 @@ def handle_incoming( %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data, _options ) do - with true <- Pleroma.Config.get([:activitypub, :accept_blocks]), - %User{local: true} = blocked = User.get_cached_by_ap_id(blocked), + with %User{local: true} = blocked = User.get_cached_by_ap_id(blocked), {:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker), {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do User.unfollow(blocker, blocked) From c1b6952d2abe55668f240947e734127664a4cefa Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 13 Aug 2019 20:34:34 +0300 Subject: [PATCH 127/202] Mastodon API: Preloading and normalization optimizations - Try to normalize the activity instead of object wherever possible - Put the `user` key on non-home timelines as well so bookmarks and thread mutes are preloaded there as well - Skip trying to get the user when rendering mentions if the id == as:Public or user's follower collection - Preload the object when getting replied to activities and do not crash if it's not present This almost solves the problem of Pleroma hammering the db with a lot of queries when rendering timelines, the things left are 1. When rendering mentions and the user is not in cache, save it for later and request all uncached users in one go 2. Somehow get rid of needing to get the latest follow activity to detect the value of `requested` in a relationship. (create a database view for user relationship and cache it maybe?) --- lib/pleroma/activity.ex | 27 +++++++++++++++++-- .../mastodon_api/mastodon_api_controller.ex | 11 +++++--- .../web/mastodon_api/views/status_view.ex | 20 +++++++++----- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 46552c7be..baf1e7722 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -224,6 +224,29 @@ def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do def get_create_by_object_ap_id(_), do: nil + def create_by_object_ap_id_with_object(ap_ids) when is_list(ap_ids) do + from( + activity in Activity, + where: + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", + activity.data, + activity.data, + ^ap_ids + ), + where: fragment("(?)->>'type' = 'Create'", activity.data), + inner_join: o in Object, + on: + fragment( + "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", + o.data, + activity.data, + activity.data + ), + preload: [object: o] + ) + end + def create_by_object_ap_id_with_object(ap_id) when is_binary(ap_id) do from( activity in Activity, @@ -263,8 +286,8 @@ defp get_in_reply_to_activity_from_object(%Object{data: %{"inReplyTo" => ap_id}} defp get_in_reply_to_activity_from_object(_), do: nil - def get_in_reply_to_activity(%Activity{data: %{"object" => object}}) do - get_in_reply_to_activity_from_object(Object.normalize(object)) + def get_in_reply_to_activity(%Activity{} = activity) do + get_in_reply_to_activity_from_object(Object.normalize(activity)) end def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"]) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 174e93468..96e0d82aa 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -435,6 +435,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) + |> Map.put("user", user) |> ActivityPub.fetch_public_activities() |> Enum.reverse() @@ -885,8 +886,8 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do end def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{data: %{"object" => object}} <- Activity.get_by_id(id), - %Object{data: %{"likes" => likes}} <- Object.normalize(object) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^likes) users = @@ -902,8 +903,8 @@ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{data: %{"object" => object}} <- Activity.get_by_id(id), - %Object{data: %{"announcements" => announces}} <- Object.normalize(object) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^announces) users = @@ -944,6 +945,7 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) + |> Map.put("user", user) |> Map.put("tag", tags) |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) @@ -1350,6 +1352,7 @@ def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) params |> Map.put("type", "Create") |> Map.put("blocking_user", user) + |> Map.put("user", user) |> Map.put("muting_user", user) # we must filter the following list for the user to avoid leaking statuses the user diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 02819e116..492af1702 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do use Pleroma.Web, :view + require Pleroma.Constants + alias Pleroma.Activity alias Pleroma.HTML alias Pleroma.Object @@ -24,19 +26,19 @@ defp get_replied_to_activities([]), do: %{} defp get_replied_to_activities(activities) do activities |> Enum.map(fn - %{data: %{"type" => "Create", "object" => object}} -> - object = Object.normalize(object) - object.data["inReplyTo"] != "" && object.data["inReplyTo"] + %{data: %{"type" => "Create"}} = activity -> + object = Object.normalize(activity) + object && object.data["inReplyTo"] != "" && object.data["inReplyTo"] _ -> nil end) |> Enum.filter(& &1) - |> Activity.create_by_object_ap_id() + |> Activity.create_by_object_ap_id_with_object() |> Repo.all() |> Enum.reduce(%{}, fn activity, acc -> object = Object.normalize(activity) - Map.put(acc, object.data["id"], activity) + if object, do: Map.put(acc, object.data["id"], activity), else: acc end) end @@ -88,6 +90,7 @@ def render( reblogged_activity = Activity.create_by_object_ap_id(activity_object.data["id"]) |> Activity.with_preloaded_bookmark(opts[:for]) + |> Activity.with_set_thread_muted_field(opts[:for]) |> Repo.one() reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) @@ -142,6 +145,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity object = Object.normalize(activity) user = get_user(activity.data["actor"]) + user_follower_address = user.follower_address like_count = object.data["like_count"] || 0 announcement_count = object.data["announcement_count"] || 0 @@ -157,7 +161,11 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity mentions = (object.data["to"] ++ tag_mentions) |> Enum.uniq() - |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end) + |> Enum.map(fn + Pleroma.Constants.as_public() -> nil + ^user_follower_address -> nil + ap_id -> User.get_cached_by_ap_id(ap_id) + end) |> Enum.filter(& &1) |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end) From 3fdbeb7087c19f2ed72a7ab60a40962d708f4cb6 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 20:28:59 +0000 Subject: [PATCH 128/202] MRF: add vocabulary policy module --- config/config.exs | 4 +++ .../web/activity_pub/mrf/vocabulary_policy.ex | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex diff --git a/config/config.exs b/config/config.exs index bf4970314..17799af59 100644 --- a/config/config.exs +++ b/config/config.exs @@ -336,6 +336,10 @@ config :pleroma, :mrf_subchain, match_actor: %{} +config :pleroma, :mrf_vocabulary, + accept: [], + reject: [] + config :pleroma, :rich_media, enabled: true, ignore_hosts: [], diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex new file mode 100644 index 000000000..de00b23da --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -0,0 +1,34 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do + @moduledoc "Filter messages which belong to certain activity vocabularies" + + @behaviour Pleroma.Web.ActivityPub.MRF + + def filter(%{"type" => "Undo", "object" => child_message} = message) do + with {:ok, _} <- filter(child_message) do + {:ok, message} + else + {:reject, nil} -> + {:reject, nil} + end + end + + def filter(%{"type" => message_type} = message) do + with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]), + rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]), + true <- + length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type), + false <- + length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type), + {:ok, _} <- filter(message["object"]) do + {:ok, message} + else + _ -> {:reject, nil} + end + end + + def filter(message), do: {:ok, message} +end From 3cfaac39e221e018b66d768521422828df1494ea Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 20:32:43 +0000 Subject: [PATCH 129/202] docs: document mrf_vocabulary module settings --- docs/config.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/config.md b/docs/config.md index d0247ef9c..fc9d4e8ef 100644 --- a/docs/config.md +++ b/docs/config.md @@ -103,6 +103,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section) + * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section) * `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. * `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send. * `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json`` @@ -276,6 +277,10 @@ config :pleroma, :mrf_subchain, ## :mrf_mention * `actors`: A list of actors, for which to drop any posts mentioning. +## :mrf_vocabulary +* `accept`: A list of ActivityStreams terms to accept. If empty, all messages are accepted. +* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected. + ## :media_proxy * `enabled`: Enables proxying of remote media to the instance’s proxy * `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts. From f7e3b7ff752f0285bea8eb92e83cf1a5cc0e05a0 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 20:55:13 +0000 Subject: [PATCH 130/202] tests: add tests for mrf_vocabulary --- .../mrf/vocabulary_policy_test.exs | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 test/web/activity_pub/mrf/vocabulary_policy_test.exs diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/web/activity_pub/mrf/vocabulary_policy_test.exs new file mode 100644 index 000000000..c3b11d7a1 --- /dev/null +++ b/test/web/activity_pub/mrf/vocabulary_policy_test.exs @@ -0,0 +1,123 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do + use Pleroma.DataCase + + alias Pleroma.Web.ActivityPub.MRF.VocabularyPolicy + + describe "accept" do + test "it accepts based on parent activity type" do + config = Pleroma.Config.get([:mrf_vocabulary, :accept]) + Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"]) + + message = %{ + "type" => "Like", + "object" => "whatever" + } + + {:ok, ^message} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :accept], config) + end + + test "it accepts based on child object type" do + config = Pleroma.Config.get([:mrf_vocabulary, :accept]) + Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) + + message = %{ + "type" => "Create", + "object" => %{ + "type" => "Note", + "content" => "whatever" + } + } + + {:ok, ^message} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :accept], config) + end + + test "it does not accept disallowed child objects" do + config = Pleroma.Config.get([:mrf_vocabulary, :accept]) + Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"]) + + message = %{ + "type" => "Create", + "object" => %{ + "type" => "Article", + "content" => "whatever" + } + } + + {:reject, nil} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :accept], config) + end + + test "it does not accept disallowed parent types" do + config = Pleroma.Config.get([:mrf_vocabulary, :accept]) + Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"]) + + message = %{ + "type" => "Create", + "object" => %{ + "type" => "Note", + "content" => "whatever" + } + } + + {:reject, nil} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :accept], config) + end + end + + describe "reject" do + test "it rejects based on parent activity type" do + config = Pleroma.Config.get([:mrf_vocabulary, :reject]) + Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) + + message = %{ + "type" => "Like", + "object" => "whatever" + } + + {:reject, nil} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :reject], config) + end + + test "it rejects based on child object type" do + config = Pleroma.Config.get([:mrf_vocabulary, :reject]) + Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"]) + + message = %{ + "type" => "Create", + "object" => %{ + "type" => "Note", + "content" => "whatever" + } + } + + {:reject, nil} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :reject], config) + end + + test "it passes through objects that aren't disallowed" do + config = Pleroma.Config.get([:mrf_vocabulary, :reject]) + Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"]) + + message = %{ + "type" => "Announce", + "object" => "whatever" + } + + {:ok, ^message} = VocabularyPolicy.filter(message) + + Pleroma.Config.put([:mrf_vocabulary, :reject], config) + end + end +end From 369d9cf03beb6f74fc6474f243734a6158f26f29 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 21:00:23 +0000 Subject: [PATCH 131/202] update changelog for mrf_vocabulary --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4229bd50..d998a4050 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) - MRF: Support for excluding specific domains from Transparency. - MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`) +- MRF: Support for filtering posts based on ActivityStreams vocabulary (`Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`) - MRF (Simple Policy): Support for wildcard domains. - Support for wildcard domains in user domain blocks setting. - Configuration: `quarantined_instances` support wildcard domains. From 04da1166db3db5b03da7dbb048e40840a6e6279f Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 13 Aug 2019 21:12:37 +0000 Subject: [PATCH 132/202] tests for /web/mastodon_api/mastodon_api.ex --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 24 +-- .../mastodon_api/mastodon_api_controller.ex | 44 +++--- .../mastodon_api_controller_test.exs | 137 ++++++++++++++---- test/web/mastodon_api/mastodon_api_test.exs | 103 +++++++++++++ 4 files changed, 243 insertions(+), 65 deletions(-) create mode 100644 test/web/mastodon_api/mastodon_api_test.exs diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 46944dcbc..ac01d1ff3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -13,10 +13,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do alias Pleroma.User alias Pleroma.Web.CommonAPI + @spec follow(User.t(), User.t(), map) :: {:ok, User.t()} | {:error, String.t()} def follow(follower, followed, params \\ %{}) do - options = cast_params(params) - reblogs = options[:reblogs] - result = if not User.following?(follower, followed) do CommonAPI.follow(follower, followed) @@ -24,19 +22,25 @@ def follow(follower, followed, params \\ %{}) do {:ok, follower, followed, nil} end - with {:ok, follower, followed, _} <- result do - reblogs - |> case do - false -> CommonAPI.hide_reblogs(follower, followed) - _ -> CommonAPI.show_reblogs(follower, followed) - end - |> case do + with {:ok, follower, _followed, _} <- result do + options = cast_params(params) + + case reblogs_visibility(options[:reblogs], result) do {:ok, follower} -> {:ok, follower} _ -> {:ok, follower} end end end + defp reblogs_visibility(false, {:ok, follower, followed, _}) do + CommonAPI.hide_reblogs(follower, followed) + end + + defp reblogs_visibility(_, {:ok, follower, followed, _}) do + CommonAPI.show_reblogs(follower, followed) + end + + @spec get_followers(User.t(), map()) :: list(User.t()) def get_followers(user, params \\ %{}) do user |> User.get_followers_query() diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 174e93468..47e263aae 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -536,8 +536,8 @@ def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do |> put_view(StatusView) |> try_render("poll.json", %{object: object, for: user}) else - nil -> render_error(conn, :not_found, "Record not found") - false -> render_error(conn, :not_found, "Record not found") + error when is_nil(error) or error == false -> + render_error(conn, :not_found, "Record not found") end end @@ -1690,45 +1690,35 @@ def suggestions(%{assigns: %{user: user}} = conn, _) do |> String.replace("{{user}}", user) with {:ok, %{status: 200, body: body}} <- - HTTP.get( - url, - [], - adapter: [ - recv_timeout: timeout, - pool: :default - ] - ), + HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]), {:ok, data} <- Jason.decode(body) do data = data |> Enum.slice(0, limit) |> Enum.map(fn x -> - Map.put( - x, - "id", - case User.get_or_fetch(x["acct"]) do - {:ok, %User{id: id}} -> id - _ -> 0 - end - ) - end) - |> Enum.map(fn x -> - Map.put(x, "avatar", MediaProxy.url(x["avatar"])) - end) - |> Enum.map(fn x -> - Map.put(x, "avatar_static", MediaProxy.url(x["avatar_static"])) + x + |> Map.put("id", fetch_suggestion_id(x)) + |> Map.put("avatar", MediaProxy.url(x["avatar"])) + |> Map.put("avatar_static", MediaProxy.url(x["avatar_static"])) end) - conn - |> json(data) + json(conn, data) else - e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") + e -> + Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") end else json(conn, []) end end + defp fetch_suggestion_id(attrs) do + case User.get_or_fetch(attrs["acct"]) do + {:ok, %User{id: id}} -> id + _ -> 0 + end + end + def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do with %Activity{} = activity <- Activity.get_by_id(status_id), true <- Visibility.visible_for_user?(activity, user) do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b023d1e4f..2febe8b3a 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Ecto.Changeset alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -85,11 +86,11 @@ test "the public timeline", %{conn: conn} do end test "the public timeline when public is set to false", %{conn: conn} do - public = Pleroma.Config.get([:instance, :public]) - Pleroma.Config.put([:instance, :public], false) + public = Config.get([:instance, :public]) + Config.put([:instance, :public], false) on_exit(fn -> - Pleroma.Config.put([:instance, :public], public) + Config.put([:instance, :public], public) end) assert conn @@ -250,7 +251,7 @@ test "posting a fake status", %{conn: conn} do end test "posting a status with OGP link preview", %{conn: conn} do - Pleroma.Config.put([:rich_media, :enabled], true) + Config.put([:rich_media, :enabled], true) conn = conn @@ -260,7 +261,7 @@ test "posting a status with OGP link preview", %{conn: conn} do assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200) assert Activity.get_by_id(id) - Pleroma.Config.put([:rich_media, :enabled], false) + Config.put([:rich_media, :enabled], false) end test "posting a direct status", %{conn: conn} do @@ -304,7 +305,7 @@ test "posting a poll", %{conn: conn} do test "option limit is enforced", %{conn: conn} do user = insert(:user) - limit = Pleroma.Config.get([:instance, :poll_limits, :max_options]) + limit = Config.get([:instance, :poll_limits, :max_options]) conn = conn @@ -320,7 +321,7 @@ test "option limit is enforced", %{conn: conn} do test "option character limit is enforced", %{conn: conn} do user = insert(:user) - limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars]) + limit = Config.get([:instance, :poll_limits, :max_option_chars]) conn = conn @@ -339,7 +340,7 @@ test "option character limit is enforced", %{conn: conn} do test "minimal date limit is enforced", %{conn: conn} do user = insert(:user) - limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration]) + limit = Config.get([:instance, :poll_limits, :min_expiration]) conn = conn @@ -358,7 +359,7 @@ test "minimal date limit is enforced", %{conn: conn} do test "maximum date limit is enforced", %{conn: conn} do user = insert(:user) - limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration]) + limit = Config.get([:instance, :poll_limits, :max_expiration]) conn = conn @@ -1633,12 +1634,12 @@ test "returns the relationships for the current user", %{conn: conn} do describe "media upload" do setup do - upload_config = Pleroma.Config.get([Pleroma.Upload]) - proxy_config = Pleroma.Config.get([:media_proxy]) + upload_config = Config.get([Pleroma.Upload]) + proxy_config = Config.get([:media_proxy]) on_exit(fn -> - Pleroma.Config.put([Pleroma.Upload], upload_config) - Pleroma.Config.put([:media_proxy], proxy_config) + Config.put([Pleroma.Upload], upload_config) + Config.put([:media_proxy], proxy_config) end) user = insert(:user) @@ -2581,7 +2582,7 @@ test "get instance information", %{conn: conn} do conn = get(conn, "/api/v1/instance") assert result = json_response(conn, 200) - email = Pleroma.Config.get([:instance, :email]) + email = Config.get([:instance, :email]) # Note: not checking for "max_toot_chars" since it's optional assert %{ "uri" => _, @@ -2666,7 +2667,7 @@ test "put settings", %{conn: conn} do describe "pinned statuses" do setup do - Pleroma.Config.put([:instance, :max_pinned_statuses], 1) + Config.put([:instance, :max_pinned_statuses], 1) user = insert(:user) {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"}) @@ -2766,10 +2767,10 @@ test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do describe "cards" do setup do - Pleroma.Config.put([:rich_media, :enabled], true) + Config.put([:rich_media, :enabled], true) on_exit(fn -> - Pleroma.Config.put([:rich_media, :enabled], false) + Config.put([:rich_media, :enabled], false) end) user = insert(:user) @@ -2997,7 +2998,7 @@ test "comment must be up to the size specified in the config", %{ reporter: reporter, target_user: target_user } do - max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000) + max_size = Config.get([:instance, :max_report_comment_size], 1000) comment = String.pad_trailing("a", max_size + 1, "a") error = %{"error" => "Comment must be up to #{max_size} characters"} @@ -3126,15 +3127,15 @@ test "redirects not logged-in users to the login page on private instances", %{ conn: conn, path: path } do - is_public = Pleroma.Config.get([:instance, :public]) - Pleroma.Config.put([:instance, :public], false) + is_public = Config.get([:instance, :public]) + Config.put([:instance, :public], false) conn = get(conn, path) assert conn.status == 302 assert redirected_to(conn) == "/web/login" - Pleroma.Config.put([:instance, :public], is_public) + Config.put([:instance, :public], is_public) end test "does not redirect logged in users to the login page", %{conn: conn, path: path} do @@ -3876,8 +3877,8 @@ test "it sends an email to user", %{user: user} do token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) - notify_email = Pleroma.Config.get([:instance, :notify_email]) - instance_name = Pleroma.Config.get([:instance, :name]) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) assert_email_sent( from: {instance_name, notify_email}, @@ -3909,11 +3910,11 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} do describe "POST /api/v1/pleroma/accounts/confirmation_resend" do setup do - setting = Pleroma.Config.get([:instance, :account_activation_required]) + setting = Config.get([:instance, :account_activation_required]) unless setting do - Pleroma.Config.put([:instance, :account_activation_required], true) - on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end) + Config.put([:instance, :account_activation_required], true) + on_exit(fn -> Config.put([:instance, :account_activation_required], setting) end) end user = insert(:user) @@ -3937,8 +3938,8 @@ test "resend account confirmation email", %{conn: conn, user: user} do |> json_response(:no_content) email = Pleroma.Emails.UserEmail.account_confirmation_email(user) - notify_email = Pleroma.Config.get([:instance, :notify_email]) - instance_name = Pleroma.Config.get([:instance, :name]) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) assert_email_sent( from: {instance_name, notify_email}, @@ -3947,4 +3948,84 @@ test "resend account confirmation email", %{conn: conn, user: user} do ) end end + + describe "GET /api/v1/suggestions" do + setup do + user = insert(:user) + other_user = insert(:user) + config = Config.get(:suggestions) + on_exit(fn -> Config.put(:suggestions, config) end) + + host = Config.get([Pleroma.Web.Endpoint, :url, :host]) + url500 = "http://test500?#{host}&#{user.nickname}" + url200 = "http://test200?#{host}&#{user.nickname}" + + mock(fn + %{method: :get, url: ^url500} -> + %Tesla.Env{status: 500, body: "bad request"} + + %{method: :get, url: ^url200} -> + %Tesla.Env{ + status: 200, + body: + ~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{ + other_user.ap_id + }","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}]) + } + end) + + [user: user, other_user: other_user] + end + + test "returns empty result when suggestions disabled", %{conn: conn, user: user} do + Config.put([:suggestions, :enabled], false) + + res = + conn + |> assign(:user, user) + |> get("/api/v1/suggestions") + |> json_response(200) + + assert res == [] + end + + test "returns error", %{conn: conn, user: user} do + Config.put([:suggestions, :enabled], true) + Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}") + + res = + conn + |> assign(:user, user) + |> get("/api/v1/suggestions") + |> json_response(500) + + assert res == "Something went wrong" + end + + test "returns suggestions", %{conn: conn, user: user, other_user: other_user} do + Config.put([:suggestions, :enabled], true) + Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}") + + res = + conn + |> assign(:user, user) + |> get("/api/v1/suggestions") + |> json_response(200) + + assert res == [ + %{ + "acct" => "yj455", + "avatar" => "https://social.heldscal.la/avatar/201.jpeg", + "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg", + "id" => 0 + }, + %{ + "acct" => other_user.ap_id, + "avatar" => "https://social.heldscal.la/avatar/202.jpeg", + "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg", + "id" => other_user.id + } + ] + end + end end diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs new file mode 100644 index 000000000..b4c0427c9 --- /dev/null +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -0,0 +1,103 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do + use Pleroma.Web.ConnCase + + alias Pleroma.Notification + alias Pleroma.ScheduledActivity + alias Pleroma.User + alias Pleroma.Web.MastodonAPI.MastodonAPI + alias Pleroma.Web.TwitterAPI.TwitterAPI + + import Pleroma.Factory + + describe "follow/3" do + test "returns error when user deactivated" do + follower = insert(:user) + user = insert(:user, local: true, info: %{deactivated: true}) + {:error, error} = MastodonAPI.follow(follower, user) + assert error == "Could not follow user: You are deactivated." + end + + test "following for user" do + follower = insert(:user) + user = insert(:user) + {:ok, follower} = MastodonAPI.follow(follower, user) + assert User.following?(follower, user) + end + + test "returns ok if user already followed" do + follower = insert(:user) + user = insert(:user) + {:ok, follower} = User.follow(follower, user) + {:ok, follower} = MastodonAPI.follow(follower, refresh_record(user)) + assert User.following?(follower, user) + end + end + + describe "get_followers/2" do + test "returns user followers" do + follower1_user = insert(:user) + follower2_user = insert(:user) + user = insert(:user) + {:ok, _follower1_user} = User.follow(follower1_user, user) + {:ok, follower2_user} = User.follow(follower2_user, user) + + assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user] + end + end + + describe "get_friends/2" do + test "returns user friends" do + user = insert(:user) + followed_one = insert(:user) + followed_two = insert(:user) + followed_three = insert(:user) + + {:ok, user} = User.follow(user, followed_one) + {:ok, user} = User.follow(user, followed_two) + {:ok, user} = User.follow(user, followed_three) + res = MastodonAPI.get_friends(user) + + assert length(res) == 3 + assert Enum.member?(res, refresh_record(followed_three)) + assert Enum.member?(res, refresh_record(followed_two)) + assert Enum.member?(res, refresh_record(followed_one)) + end + end + + describe "get_notifications/2" do + test "returns notifications for user" do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) + {:ok, status1} = TwitterAPI.create_status(user, %{"status" => "Magi"}) + {:ok, [notification]} = Notification.create_notifications(status) + {:ok, [notification1]} = Notification.create_notifications(status1) + res = MastodonAPI.get_notifications(subscriber) + + assert Enum.member?(Enum.map(res, & &1.id), notification.id) + assert Enum.member?(Enum.map(res, & &1.id), notification1.id) + end + end + + describe "get_scheduled_activities/2" do + test "returns user scheduled activities" do + user = insert(:user) + + today = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + + attrs = %{params: %{}, scheduled_at: today} + {:ok, schedule} = ScheduledActivity.create(user, attrs) + assert MastodonAPI.get_scheduled_activities(user) == [schedule] + end + end +end From fea4d89e9f59b6fbdbd727eecde9b046e9ca46c6 Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 13 Aug 2019 21:12:59 +0000 Subject: [PATCH 133/202] tests for Web/ActivityPub/Relay --- lib/pleroma/web/activity_pub/relay.ex | 17 +++++++- test/web/activity_pub/relay_test.exs | 62 ++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 1ebfcdd86..5f18cc64a 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -14,6 +14,7 @@ def get_actor do |> User.get_or_create_service_actor_by_ap_id() end + @spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()} def follow(target_instance) do with %User{} = local_user <- get_actor(), {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), @@ -21,12 +22,17 @@ def follow(target_instance) do Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}") {:ok, activity} else + {:error, _} = error -> + Logger.error("error: #{inspect(error)}") + error + e -> Logger.error("error: #{inspect(e)}") {:error, e} end end + @spec unfollow(String.t()) :: {:ok, Activity.t()} | {:error, any()} def unfollow(target_instance) do with %User{} = local_user <- get_actor(), {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), @@ -34,20 +40,27 @@ def unfollow(target_instance) do Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") {:ok, activity} else + {:error, _} = error -> + Logger.error("error: #{inspect(error)}") + error + e -> Logger.error("error: #{inspect(e)}") {:error, e} end end + @spec publish(any()) :: {:ok, Activity.t(), Object.t()} | {:error, any()} def publish(%Activity{data: %{"type" => "Create"}} = activity) do with %User{} = user <- get_actor(), %Object{} = object <- Object.normalize(activity) do ActivityPub.announce(user, object, nil, true, false) else - e -> Logger.error("error: #{inspect(e)}") + e -> + Logger.error("error: #{inspect(e)}") + {:error, inspect(e)} end end - def publish(_), do: nil + def publish(_), do: {:error, "Not implemented"} end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 21a63c493..e10b808f7 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -5,11 +5,71 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do use Pleroma.DataCase + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay + import Pleroma.Factory + test "gets an actor for the relay" do user = Relay.get_actor() + assert user.ap_id == "#{Pleroma.Web.Endpoint.url()}/relay" + end - assert user.ap_id =~ "/relay" + describe "follow/1" do + test "returns errors when user not found" do + assert Relay.follow("test-ap-id") == {:error, "Could not fetch by AP id"} + end + + test "returns activity" do + user = insert(:user) + service_actor = Relay.get_actor() + assert {:ok, %Activity{} = activity} = Relay.follow(user.ap_id) + assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" + assert user.ap_id in activity.recipients + assert activity.data["type"] == "Follow" + assert activity.data["actor"] == service_actor.ap_id + assert activity.data["object"] == user.ap_id + end + end + + describe "unfollow/1" do + test "returns errors when user not found" do + assert Relay.unfollow("test-ap-id") == {:error, "Could not fetch by AP id"} + end + + test "returns activity" do + user = insert(:user) + service_actor = Relay.get_actor() + ActivityPub.follow(service_actor, user) + assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id) + assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" + assert user.ap_id in activity.recipients + assert activity.data["type"] == "Undo" + assert activity.data["actor"] == service_actor.ap_id + assert activity.data["to"] == [user.ap_id] + end + end + + describe "publish/1" do + test "returns error when activity not `Create` type" do + activity = insert(:like_activity) + assert Relay.publish(activity) == {:error, "Not implemented"} + end + + test "returns error when activity not public" do + activity = insert(:direct_note_activity) + assert Relay.publish(activity) == {:error, false} + end + + test "returns announce activity" do + service_actor = Relay.get_actor() + note = insert(:note_activity) + assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) + assert activity.data["type"] == "Announce" + assert activity.data["actor"] == service_actor.ap_id + assert activity.data["object"] == obj.data["id"] + end end end From 694bc43123a79293b02585bc457d08b0fbb1f103 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 21:26:24 +0000 Subject: [PATCH 134/202] MRF: add describe() for gathering and describing the MRF configuration --- lib/pleroma/web/activity_pub/mrf.ex | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index caa2a3231..d43a8760b 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -35,4 +35,20 @@ def subdomains_regex(domains) when is_list(domains) do def subdomain_match?(domains, host) do Enum.any?(domains, fn domain -> Regex.match?(domain, host) end) end + + @callback describe() :: {:ok | :error, Map.t()} + + def describe(policies) do + policies + |> Enum.reduce({:ok, %{}}, fn + policy, {:ok, data} -> + {:ok, policy_data} = policy.describe() + {:ok, Map.merge(data, policy_data)} + + _, error -> + error + end) + end + + def describe(), do: get_policies() |> describe() end From 7089400675ddc05cf29591a4109d8a96c173ad99 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 21:29:15 +0000 Subject: [PATCH 135/202] test: add mock MRF module for describe() testing --- test/support/mrf_module_mock.ex | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/support/mrf_module_mock.ex diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex new file mode 100644 index 000000000..e5ae21ad8 --- /dev/null +++ b/test/support/mrf_module_mock.ex @@ -0,0 +1,13 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule MRFModuleMock do + @behaviour Pleroma.Web.ActivityPub.MRF + + @impl true + def filter(message), do: {:ok, message} + + @impl true + def describe(), do: %{"mrf_module_mock" => "some config data"} +end From c574b7a1fcc0556b5fd86d48283a2885c05ebc69 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 21:52:54 +0000 Subject: [PATCH 136/202] MRF: add describe() to all modules, add base MRF configuration to base describe() --- lib/pleroma/web/activity_pub/mrf.ex | 32 ++++++++++++++----- .../activity_pub/mrf/anti_followbot_policy.ex | 3 ++ .../activity_pub/mrf/anti_link_spam_policy.ex | 6 ++++ .../web/activity_pub/mrf/drop_policy.ex | 3 ++ .../activity_pub/mrf/ensure_re_prepended.ex | 2 ++ .../web/activity_pub/mrf/hellthread_policy.ex | 3 ++ .../web/activity_pub/mrf/keyword_policy.ex | 32 +++++++++++++++++++ .../mrf/mediaproxy_warming_policy.ex | 3 ++ .../web/activity_pub/mrf/mention_policy.ex | 3 ++ .../mrf/no_placeholder_text_policy.ex | 3 ++ .../web/activity_pub/mrf/noop_policy.ex | 3 ++ .../web/activity_pub/mrf/normalize_markup.ex | 2 ++ .../web/activity_pub/mrf/reject_non_public.ex | 3 ++ .../web/activity_pub/mrf/simple_policy.ex | 12 +++++++ .../web/activity_pub/mrf/subchain_policy.ex | 3 ++ .../web/activity_pub/mrf/tag_policy.ex | 3 ++ .../activity_pub/mrf/user_allowlist_policy.ex | 9 ++++++ 17 files changed, 117 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index d43a8760b..7533552d5 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -39,15 +39,31 @@ def subdomain_match?(domains, host) do @callback describe() :: {:ok | :error, Map.t()} def describe(policies) do - policies - |> Enum.reduce({:ok, %{}}, fn - policy, {:ok, data} -> - {:ok, policy_data} = policy.describe() - {:ok, Map.merge(data, policy_data)} + {:ok, policy_configs} = + policies + |> Enum.reduce({:ok, %{}}, fn + policy, {:ok, data} -> + {:ok, policy_data} = policy.describe() + {:ok, Map.merge(data, policy_data)} - _, error -> - error - end) + _, error -> + error + end) + + mrf_policies = + get_policies() + |> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end) + + exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions]) + + base = + %{ + mrf_policies: mrf_policies, + exclusions: length(exclusions) > 0, + } + |> Map.merge(policy_configs) + + {:ok, base} end def describe(), do: get_policies() |> describe() diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex index 87fa514c3..ad2d9bf54 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex @@ -62,4 +62,7 @@ def filter(%{"type" => "Follow", "actor" => actor_id} = message) do @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index 2da3eac2f..d27386591 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do alias Pleroma.User + @behaviour Pleroma.Web.ActivityPub.MRF + require Logger # has the user successfully posted before? @@ -22,6 +24,7 @@ defp contains_links?(%{"content" => content} = _object) do defp contains_links?(_), do: false + @impl true def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor), {:contains_links, true} <- {:contains_links, contains_links?(object)}, @@ -45,4 +48,7 @@ def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message # in all other cases, pass through def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex index b8d38aae6..dcb640b12 100644 --- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex @@ -12,4 +12,7 @@ def filter(object) do Logger.info("REJECTING #{inspect(object)}") {:reject, object} end + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex index 2d03df68a..df8dc88d5 100644 --- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex +++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex @@ -39,4 +39,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do end def filter(object), do: {:ok, object} + + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index 377987cf2..ef717fa43 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -90,4 +90,7 @@ def filter(%{"type" => "Create"} = message) do @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}} end diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex index 4eec8b916..fbfe7a7eb 100644 --- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -96,4 +96,36 @@ def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message @impl true def filter(message), do: {:ok, message} + + @impl true + def describe() do + # This horror is needed to convert regex sigils to strings + mrf_keyword = + Pleroma.Config.get(:mrf_keyword, []) + |> Enum.map(fn {key, value} -> + {key, + Enum.map(value, fn + {pattern, replacement} -> + %{ + "pattern" => + if not is_binary(pattern) do + inspect(pattern) + else + pattern + end, + "replacement" => replacement + } + + pattern -> + if not is_binary(pattern) do + inspect(pattern) + else + pattern + end + end)} + end) + |> Enum.into(%{}) + + {:ok, %{mrf_keyword: mrf_keyword}} + end end diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index 01d21a299..f38b42794 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -53,4 +53,7 @@ def filter( @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex index 1842e1aeb..49717d45d 100644 --- a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex @@ -21,4 +21,7 @@ def filter(%{"type" => "Create"} = message) do @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex index 86a48bda5..6fc9544a0 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex @@ -19,4 +19,7 @@ def filter( @impl true def filter(object), do: {:ok, object} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex index c47cb3298..19890ef0c 100644 --- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex @@ -10,4 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do def filter(object) do {:ok, object} end + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex index c269d0f89..b684a3505 100644 --- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex +++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex @@ -21,4 +21,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do end def filter(object), do: {:ok, object} + + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index 457b6ee10..39ebf456a 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -44,4 +44,7 @@ def filter(%{"type" => "Create"} = object) do @impl true def filter(object), do: {:ok, object} + + @impl true + def describe(), do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}} end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index f266457e3..89e0e3d54 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -177,4 +177,16 @@ def filter(%{"id" => actor, "type" => obj_type} = object) end def filter(object), do: {:ok, object} + + @impl true + def describe() do + exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions]) + + mrf_simple = + Pleroma.Config.get(:mrf_simple) + |> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end) + |> Enum.into(%{}) + + {:ok, %{mrf_simple: mrf_simple}} + end end diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex index 765704389..b69410ca8 100644 --- a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex @@ -37,4 +37,7 @@ def filter(%{"actor" => actor} = message) do @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 70edf4f7f..95864156f 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -165,4 +165,7 @@ def filter(%{"actor" => actor, "type" => "Create"} = message), @impl true def filter(message), do: {:ok, message} + + @impl true + def describe(), do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex index e35d2c422..c2597da8f 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex @@ -32,4 +32,13 @@ def filter(%{"actor" => actor} = object) do end def filter(object), do: {:ok, object} + + @impl true + def describe() do + mrf_user_allowlist = + Config.get([:mrf_user_allowlist], []) + |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) + + {:ok, %{mrf_user_allowlist: mrf_user_allowlist}} + end end From f305e97eeb1ee036d78e2f75f468b1e165d04356 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 21:57:39 +0000 Subject: [PATCH 137/202] nodeinfo: use MRF.describe() instead of hardcoded MRF transparency stuff --- .../web/nodeinfo/nodeinfo_controller.ex | 54 ++----------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 54f89e65c..ee14cfd6b 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -34,64 +34,18 @@ def schemas(conn, _params) do def raw_nodeinfo do stats = Stats.get_stats() - exclusions = Config.get([:instance, :mrf_transparency_exclusions]) - - mrf_simple = - Config.get(:mrf_simple) - |> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end) - |> Enum.into(%{}) - - # This horror is needed to convert regex sigils to strings - mrf_keyword = - Config.get(:mrf_keyword, []) - |> Enum.map(fn {key, value} -> - {key, - Enum.map(value, fn - {pattern, replacement} -> - %{ - "pattern" => - if not is_binary(pattern) do - inspect(pattern) - else - pattern - end, - "replacement" => replacement - } - - pattern -> - if not is_binary(pattern) do - inspect(pattern) - else - pattern - end - end)} - end) - |> Enum.into(%{}) - - mrf_policies = - MRF.get_policies() - |> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end) - quarantined = Config.get([:instance, :quarantined_instances], []) staff_accounts = User.all_superusers() |> Enum.map(fn u -> u.ap_id end) - mrf_user_allowlist = - Config.get([:mrf_user_allowlist], []) - |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) - federation_response = if Config.get([:instance, :mrf_transparency]) do - %{ - mrf_policies: mrf_policies, - mrf_simple: mrf_simple, - mrf_keyword: mrf_keyword, - mrf_user_allowlist: mrf_user_allowlist, - quarantined_instances: quarantined, - exclusions: length(exclusions) > 0 - } + {:ok, data} = MRF.describe() + + data + |> Map.merge(%{quarantined_instances: quarantined}) else %{} end From 46d7bef7e7cf63728055a30cbe6cafdda0c9c3d3 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 14 Aug 2019 01:15:18 +0300 Subject: [PATCH 138/202] Nicer formatting for safe_render errors --- lib/pleroma/web/web.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex index b42f6887e..687346554 100644 --- a/lib/pleroma/web/web.ex +++ b/lib/pleroma/web/web.ex @@ -58,10 +58,10 @@ def safe_render(view, template, assigns \\ %{}) do rescue error -> Logger.error( - "#{__MODULE__} failed to render #{inspect({view, template})}: #{inspect(error)}" + "#{__MODULE__} failed to render #{inspect({view, template})}\n" <> + Exception.format(:error, error, __STACKTRACE__) ) - Logger.error(inspect(__STACKTRACE__)) nil end From dd0b71ea6d0b758ee5425f295a8ee14f33c4ec07 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 22:19:15 +0000 Subject: [PATCH 139/202] tests: add tests for MRF.describe() --- test/support/mrf_module_mock.ex | 2 +- test/web/activity_pub/mrf/mrf_test.exs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex index e5ae21ad8..573eb0147 100644 --- a/test/support/mrf_module_mock.ex +++ b/test/support/mrf_module_mock.ex @@ -9,5 +9,5 @@ defmodule MRFModuleMock do def filter(message), do: {:ok, message} @impl true - def describe(), do: %{"mrf_module_mock" => "some config data"} + def describe(), do: {:ok, %{mrf_module_mock: "some config data"}} end diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/web/activity_pub/mrf/mrf_test.exs index 1a888e18f..19e172939 100644 --- a/test/web/activity_pub/mrf/mrf_test.exs +++ b/test/web/activity_pub/mrf/mrf_test.exs @@ -57,4 +57,30 @@ test "matches are case-insensitive" do refute MRF.subdomain_match?(regexes, "example.com") end end + + describe "describe/0" do + test "it works as expected with noop policy" do + expected = %{ + mrf_policies: ["NoOpPolicy"], + exclusions: false + } + + {:ok, ^expected} = MRF.describe() + end + + test "it works as expected with mock policy" do + config = Pleroma.Config.get([:instance, :rewrite_policy]) + Pleroma.Config.put([:instance, :rewrite_policy], [MRFModuleMock]) + + expected = %{ + mrf_policies: ["MRFModuleMock"], + mrf_module_mock: "some config data", + exclusions: false + } + + {:ok, ^expected} = MRF.describe() + + Pleroma.Config.put([:instance, :rewrite_policy], config) + end + end end From 10fef2fceee6d527d3fae0f67d81868b457d71b1 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 22:32:40 +0000 Subject: [PATCH 140/202] tests: fix up nodeinfo tests --- test/web/node_info_test.exs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index d7f848bfa..f6147c286 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -85,6 +85,9 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do end test "it shows MRF transparency data if enabled", %{conn: conn} do + config = Pleroma.Config.get([:instance, :rewrite_policy]) + Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) + option = Pleroma.Config.get([:instance, :mrf_transparency]) Pleroma.Config.put([:instance, :mrf_transparency], true) @@ -98,11 +101,15 @@ test "it shows MRF transparency data if enabled", %{conn: conn} do assert response["metadata"]["federation"]["mrf_simple"] == simple_config + Pleroma.Config.put([:instance, :rewrite_policy], config) Pleroma.Config.put([:instance, :mrf_transparency], option) Pleroma.Config.put(:mrf_simple, %{}) end test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do + config = Pleroma.Config.get([:instance, :rewrite_policy]) + Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) + option = Pleroma.Config.get([:instance, :mrf_transparency]) Pleroma.Config.put([:instance, :mrf_transparency], true) @@ -122,6 +129,7 @@ test "it performs exclusions from MRF transparency data if configured", %{conn: assert response["metadata"]["federation"]["mrf_simple"] == expected_config assert response["metadata"]["federation"]["exclusions"] == true + Pleroma.Config.put([:instance, :rewrite_policy], config) Pleroma.Config.put([:instance, :mrf_transparency], option) Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions) Pleroma.Config.put(:mrf_simple, %{}) From 4244e17de0da9978bad6afb1922a3e9cf36996bb Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 22:36:24 +0000 Subject: [PATCH 141/202] fix credo --- lib/pleroma/web/activity_pub/mrf.ex | 4 ++-- lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex | 2 +- lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/keyword_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/mention_policy.ex | 2 +- .../web/activity_pub/mrf/no_placeholder_text_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/noop_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/normalize_markup.ex | 2 +- lib/pleroma/web/activity_pub/mrf/reject_non_public.ex | 2 +- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/subchain_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex | 2 +- test/support/mrf_module_mock.ex | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 7533552d5..263ed11af 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -59,12 +59,12 @@ def describe(policies) do base = %{ mrf_policies: mrf_policies, - exclusions: length(exclusions) > 0, + exclusions: length(exclusions) > 0 } |> Map.merge(policy_configs) {:ok, base} end - def describe(), do: get_policies() |> describe() + def describe, do: get_policies() |> describe() end diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex index ad2d9bf54..de1eb4aa5 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex @@ -64,5 +64,5 @@ def filter(%{"type" => "Follow", "actor" => actor_id} = message) do def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index d27386591..b90193ca0 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -50,5 +50,5 @@ def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex index dcb640b12..f7831bc3e 100644 --- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex @@ -14,5 +14,5 @@ def filter(object) do end @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex index df8dc88d5..3a3e72910 100644 --- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex +++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex @@ -40,5 +40,5 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do def filter(object), do: {:ok, object} - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index ef717fa43..9863454fa 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -92,5 +92,5 @@ def filter(%{"type" => "Create"} = message) do def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}} + def describe, do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}} end diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex index fbfe7a7eb..d6d1396bc 100644 --- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -98,7 +98,7 @@ def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message def filter(message), do: {:ok, message} @impl true - def describe() do + def describe do # This horror is needed to convert regex sigils to strings mrf_keyword = Pleroma.Config.get(:mrf_keyword, []) diff --git a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex index f38b42794..a179dd54d 100644 --- a/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mediaproxy_warming_policy.ex @@ -55,5 +55,5 @@ def filter( def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex index 49717d45d..ce8bc4580 100644 --- a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex @@ -23,5 +23,5 @@ def filter(%{"type" => "Create"} = message) do def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex index 6fc9544a0..f67f48ab6 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex @@ -21,5 +21,5 @@ def filter( def filter(object), do: {:ok, object} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex index 19890ef0c..878c57925 100644 --- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex @@ -12,5 +12,5 @@ def filter(object) do end @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex index b684a3505..daa4c88ad 100644 --- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex +++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex @@ -22,5 +22,5 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do def filter(object), do: {:ok, object} - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index 39ebf456a..0ae9397ed 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -46,5 +46,5 @@ def filter(%{"type" => "Create"} = object) do def filter(object), do: {:ok, object} @impl true - def describe(), do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}} + def describe, do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}} end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 89e0e3d54..8aa6852f0 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -179,7 +179,7 @@ def filter(%{"id" => actor, "type" => obj_type} = object) def filter(object), do: {:ok, object} @impl true - def describe() do + def describe do exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions]) mrf_simple = diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex index b69410ca8..566c1e191 100644 --- a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex @@ -39,5 +39,5 @@ def filter(%{"actor" => actor} = message) do def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 95864156f..c1801d2ec 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -167,5 +167,5 @@ def filter(%{"actor" => actor, "type" => "Create"} = message), def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{}} + def describe, do: {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex index c2597da8f..7389d6a96 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist_policy.ex @@ -34,7 +34,7 @@ def filter(%{"actor" => actor} = object) do def filter(object), do: {:ok, object} @impl true - def describe() do + def describe do mrf_user_allowlist = Config.get([:mrf_user_allowlist], []) |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex index 573eb0147..12c7e22bc 100644 --- a/test/support/mrf_module_mock.ex +++ b/test/support/mrf_module_mock.ex @@ -9,5 +9,5 @@ defmodule MRFModuleMock do def filter(message), do: {:ok, message} @impl true - def describe(), do: {:ok, %{mrf_module_mock: "some config data"}} + def describe, do: {:ok, %{mrf_module_mock: "some config data"}} end From abfbcfdcb31a034d5512c69568bbb7607c0afdc8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 22:39:26 +0000 Subject: [PATCH 142/202] mrf_vocabulary: add describe API support --- lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index de00b23da..74da8d57e 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -31,4 +31,6 @@ def filter(%{"type" => message_type} = message) do end def filter(message), do: {:ok, message} + + def describe, do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary)}} end From 5983f98f2618d5e744337f1f79b78c3ad2774d9c Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Tue, 13 Aug 2019 22:40:18 +0000 Subject: [PATCH 143/202] docs tweak --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index fc9d4e8ef..d1fa501ea 100644 --- a/docs/config.md +++ b/docs/config.md @@ -278,7 +278,7 @@ config :pleroma, :mrf_subchain, * `actors`: A list of actors, for which to drop any posts mentioning. ## :mrf_vocabulary -* `accept`: A list of ActivityStreams terms to accept. If empty, all messages are accepted. +* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted. * `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected. ## :media_proxy From f4e087ee485bd6766e426627eeaa729779b5eabc Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 14 Aug 2019 02:36:54 +0300 Subject: [PATCH 144/202] Preload thread mutes/bookmarks in get_context Also removes filtering for creates (was done on the database side already) and filtering for the requested activity (moved to the database side) from application side. --- lib/pleroma/web/activity_pub/activity_pub.ex | 9 +++++++++ lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 7 ++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1a279a7df..d473a3ed9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -518,6 +518,8 @@ defp fetch_activities_for_context_query(context, opts) do from(activity in Activity) |> maybe_preload_objects(opts) + |> maybe_preload_bookmarks(opts) + |> maybe_set_thread_muted_field(opts) |> restrict_blocked(opts) |> restrict_recipients(recipients, opts["user"]) |> where( @@ -531,6 +533,7 @@ defp fetch_activities_for_context_query(context, opts) do ) ) |> exclude_poll_votes(opts) + |> exclude_id(opts) |> order_by([activity], desc: activity.id) end @@ -870,6 +873,12 @@ defp exclude_poll_votes(query, _) do end end + defp exclude_id(query, %{"exclude_id" => id}) when is_binary(id) do + from(activity in query, where: activity.id != ^id) + end + + defp exclude_id(query, _), do: query + defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query defp maybe_preload_objects(query, _) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index c3c75bd9a..7ce2b5b06 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -497,12 +497,9 @@ def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do activities <- ActivityPub.fetch_activities_for_context(activity.data["context"], %{ "blocking_user" => user, - "user" => user + "user" => user, + "exclude_id" => activity.id }), - activities <- - activities |> Enum.filter(fn %{id: aid} -> to_string(aid) != to_string(id) end), - activities <- - activities |> Enum.filter(fn %{data: %{"type" => type}} -> type == "Create" end), grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do result = %{ ancestors: From 8202f1634a14037081cbef839e3fe528c6ca48b5 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 14 Aug 2019 03:02:09 +0300 Subject: [PATCH 145/202] Preload thread mutes/bookmarks in user_statuses --- lib/pleroma/web/activity_pub/activity_pub.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1a279a7df..44ff20af6 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -623,6 +623,7 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do params = params |> Map.put("type", ["Create", "Announce"]) + |> Map.put("user", reading_user) |> Map.put("actor_id", user.ap_id) |> Map.put("whole_db", true) |> Map.put("pinned_activity_ids", user.info.pinned_activities) From 8fab9c5c1c631d3f265f6c999dd116e947814339 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Aug 2019 01:36:42 +0000 Subject: [PATCH 146/202] update changelog to cover MRF describe API. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7548a546a..358287096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MRF: ensure that subdomain_match calls are case-insensitive ### Added +- **Breaking:** MRF describe API, which adds support for exposing configuration information about MRF policies to NodeInfo. + Custom modules will need to be updated by adding, at the very least, `def describe, do: {:ok, %{}}` to the MRF policy modules. - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) - MRF: Support for excluding specific domains from Transparency. - MRF: Support for filtering posts based on who they mention (`Pleroma.Web.ActivityPub.MRF.MentionPolicy`) From e0ac5c7a66664c897e1b3af9a55e0b73f32fa034 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 24 Jul 2019 19:26:35 +0700 Subject: [PATCH 147/202] Add custom profile fields --- config/config.exs | 1 + docs/config.md | 1 + lib/pleroma/user/info.ex | 31 +++++++++++++++ .../mastodon_api/mastodon_api_controller.ex | 11 ++++++ .../web/mastodon_api/views/account_view.ex | 9 ++--- .../update_credentials_test.exs | 39 +++++++++++++++++++ 6 files changed, 87 insertions(+), 5 deletions(-) diff --git a/config/config.exs b/config/config.exs index 758661120..109cf6516 100644 --- a/config/config.exs +++ b/config/config.exs @@ -255,6 +255,7 @@ dynamic_configuration: false, user_bio_length: 5000, user_name_length: 100, + max_account_fields: 4, external_user_synchronization: true config :pleroma, :markup, diff --git a/docs/config.md b/docs/config.md index 20311db54..ca5da7db1 100644 --- a/docs/config.md +++ b/docs/config.md @@ -132,6 +132,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `skip_thread_containment`: Skip filter out broken threads. The default is `false`. * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. +* `max_account_fields`: The maximum number of custom fields in the user profile (default: `4`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 22eb9a182..fa57052fb 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -49,6 +49,7 @@ defmodule Pleroma.User.Info do field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) field(:pleroma_settings_store, :map, default: %{}) + field(:fields, {:array, :map}, default: []) field(:notification_settings, :map, default: %{ @@ -286,10 +287,32 @@ def profile_update(info, params) do :background, :show_role, :skip_thread_containment, + :fields, :pleroma_settings_store ]) + |> validate_fields() end + def validate_fields(changeset) do + limit = Pleroma.Config.get([:instance, :max_account_fields], 0) + + changeset + |> validate_length(:fields, max: limit) + |> validate_change(:fields, fn :fields, fields -> + if Enum.all?(fields, &valid_field?/1) do + [] + else + [fields: "invalid"] + end + end) + end + + defp valid_field?(%{"name" => name, "value" => value}) do + is_binary(name) && is_binary(value) + end + + defp valid_field?(_), do: false + @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t() def confirmation_changeset(info, opts) do need_confirmation? = Keyword.get(opts, :need_confirmation) @@ -384,6 +407,14 @@ def remove_reblog_mute(info, ap_id) do cast(info, params, [:muted_reblogs]) end + def fields(%{source_data: %{"attachment" => attachment}}) do + attachment + |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) + |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + end + + def fields(%{fields: fields}), do: fields + def follow_information_update(info, params) do info |> cast(params, [ diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 7ce2b5b06..e79a02caa 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -156,6 +156,17 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end) end) |> add_if_present(params, "default_scope", :default_scope) + |> add_if_present(params, "fields", :fields, fn fields -> + fields = + Enum.map(fields, fn field -> + %{ + "name" => Formatter.html_escape(field["name"], "text/plain"), + "value" => Formatter.html_escape(field["value"], "text/plain") + } + end) + + {:ok, fields} + end) |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value -> {:ok, Map.merge(user.info.pleroma_settings_store, value)} end) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 72c092f25..d2f3986ff 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -93,10 +93,8 @@ defp do_render("account.json", %{user: user} = opts) do } end) - fields = - (user.info.source_data["attachment"] || []) - |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) - |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + fields = User.Info.fields(user.info) + fields_html = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) @@ -119,11 +117,12 @@ defp do_render("account.json", %{user: user} = opts) do header: header, header_static: header, emojis: emojis, - fields: fields, + fields: fields_html, bot: bot, source: %{ note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, + fields: fields, pleroma: %{} }, diff --git a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs index 71d0c8af8..a3eadde16 100644 --- a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs @@ -300,5 +300,44 @@ test "updates profile emojos", %{conn: conn} do assert user["display_name"] == name assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"] end + + test "update fields", %{conn: conn} do + user = insert(:user) + + fields = [ + %{"name" => "foo", "value" => "bar"}, + %{"name" => "link", "value" => "cofe.io"} + ] + + account = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) + |> json_response(200) + + assert account["fields"] == [ + %{"name" => "<b>foo<b>", "value" => "<i>bar</i>"}, + %{"name" => "link", "value" => "
cofe.io"} + ] + + assert account["source"]["fields"] == [ + %{"name" => "<b>foo<b>", "value" => "<i>bar</i>"}, + %{"name" => "link", "value" => "cofe.io"} + ] + + Pleroma.Config.put([:instance, :max_account_fields], 1) + + fields = [ + %{"name" => "foo", "value" => "bar"}, + %{"name" => "link", "value" => "cofe.io"} + ] + + conn = + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) + + assert %{"error" => "Invalid request"} == json_response(conn, 403) + end end end From d6094b405d1a744eaa1c17752b3088dfee16c8d2 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 24 Jul 2019 19:48:15 +0700 Subject: [PATCH 148/202] Fix tests --- test/web/mastodon_api/account_view_test.exs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index a26f514a5..1d8b28339 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -67,7 +67,8 @@ test "Represent a user account" do source: %{ note: "valid html", sensitive: false, - pleroma: %{} + pleroma: %{}, + fields: [] }, pleroma: %{ background_image: "https://example.com/images/asuka_hospital.png", @@ -134,7 +135,8 @@ test "Represent a Service(bot) account" do source: %{ note: user.bio, sensitive: false, - pleroma: %{} + pleroma: %{}, + fields: [] }, pleroma: %{ background_image: nil, @@ -304,7 +306,8 @@ test "represent an embedded relationship" do source: %{ note: user.bio, sensitive: false, - pleroma: %{} + pleroma: %{}, + fields: [] }, pleroma: %{ background_image: nil, From 069951722f9b674a759e0b8683aff9c03019467b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 25 Jul 2019 14:34:52 +0700 Subject: [PATCH 149/202] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 358287096..a54b04658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add `pleroma.deactivated` to the Account entity - Mastodon API: added `/auth/password` endpoint for password reset with rate limit. - Mastodon API: /api/v1/accounts/:id/statuses now supports nicknames or user id +- Mastodon API: Add support for the user profile custom fields - Admin API: Return users' tags when querying reports - Admin API: Return avatar and display name when querying users - Admin API: Allow querying user by ID From a22f540fc42dd941631e94fe931d1f655b2904a1 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 25 Jul 2019 19:33:18 +0700 Subject: [PATCH 150/202] Add custom fields to TwitterAPI.UserView --- lib/pleroma/user/info.ex | 2 ++ lib/pleroma/web/twitter_api/views/user_view.ex | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index fa57052fb..98b894223 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -407,6 +407,8 @@ def remove_reblog_mute(info, ap_id) do cast(info, params, [:muted_reblogs]) end + # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. + # For example: [{"name": "Pronoun", "value": "she/her"}, …] def fields(%{source_data: %{"attachment" => attachment}}) do attachment |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 8d8892068..3681773be 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -74,12 +74,7 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do |> HTML.filter_tags(User.html_filter_policy(for_user)) |> Formatter.emojify(emoji) - # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. - # For example: [{"name": "Pronoun", "value": "she/her"}, …] - fields = - (user.info.source_data["attachment"] || []) - |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) - |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + fields = User.Info.fields(user.info) data = %{ From 88598c9bafcdcf89b0f1fb00d0785c77b583cd65 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 25 Jul 2019 19:35:34 +0700 Subject: [PATCH 151/202] Add profile custom fields to ActivityPub.UserView --- lib/pleroma/web/activity_pub/views/user_view.ex | 6 ++++++ test/web/activity_pub/views/user_view_test.exs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 06c9e1c71..7b4bc998b 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -80,6 +80,11 @@ def render("user.json", %{user: user}) do |> Transmogrifier.add_emoji_tags() |> Map.get("tag", []) + fields = + user.info + |> User.Info.fields() + |> Enum.map(&Map.put(&1, "type", "PropertyValue")) + %{ "id" => user.ap_id, "type" => "Person", @@ -98,6 +103,7 @@ def render("user.json", %{user: user}) do "publicKeyPem" => public_key }, "endpoints" => endpoints, + "attachment" => fields, "tag" => (user.info.source_data["tag"] || []) ++ user_tags } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 86254117f..48a522c6c 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -22,6 +22,22 @@ test "Renders a user, including the public key" do assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY") end + test "Renders profile fields" do + fields = [ + %{"name" => "foo", "value" => "bar"}, + %{"name" => "website", "value" => "cofe.my"} + ] + + user = insert(:user, info: %{fields: fields}) + + assert %{ + "attachment" => [ + %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, + %{"name" => "website", "type" => "PropertyValue", "value" => "cofe.my"} + ] + } = UserView.render("user.json", %{user: user}) + end + test "Does not add an avatar image if the user hasn't set one" do user = insert(:user) {:ok, user} = User.ensure_keys_present(user) From 8ab87ce40b0b8a5be7cd3576eddbacc279d8d3a1 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 26 Jul 2019 12:08:46 +0000 Subject: [PATCH 152/202] Apply suggestion to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a54b04658..483c88073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,7 +64,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add `pleroma.deactivated` to the Account entity - Mastodon API: added `/auth/password` endpoint for password reset with rate limit. - Mastodon API: /api/v1/accounts/:id/statuses now supports nicknames or user id -- Mastodon API: Add support for the user profile custom fields +- Mastodon API: Improve support for the user profile custom fields - Admin API: Return users' tags when querying reports - Admin API: Return avatar and display name when querying users - Admin API: Allow querying user by ID From 5178f960c3f5a35e2071bd5463b537cadc9a53af Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 29 Jul 2019 19:01:15 +0700 Subject: [PATCH 153/202] Support user attachment update in Transmogrifier --- .../web/activity_pub/transmogrifier.ex | 2 + test/fixtures/mastodon-update.json | 36 +++++++++--- .../tesla_mock/admin@mastdon.example.org.json | 55 ++++++++++++++++++- test/web/activity_pub/transmogrifier_test.exs | 36 ++++++++++++ 4 files changed, 120 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 0fcc81bf3..225c34875 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -598,11 +598,13 @@ def handle_incoming( banner = new_user_data[:info][:banner] locked = new_user_data[:info][:locked] || false + attachment = get_in(new_user_data, [:info, "source_data", "attachment"]) update_data = new_user_data |> Map.take([:name, :bio, :avatar]) |> Map.put(:info, %{banner: banner, locked: locked}) + |> Map.put(:info, %{"banner" => banner, "locked" => locked, "source_data" => source_data}) actor |> User.upgrade_changeset(update_data) diff --git a/test/fixtures/mastodon-update.json b/test/fixtures/mastodon-update.json index f6713fea5..dbf8b6dff 100644 --- a/test/fixtures/mastodon-update.json +++ b/test/fixtures/mastodon-update.json @@ -1,10 +1,10 @@ -{ - "type": "Update", - "object": { - "url": "http://mastodon.example.org/@gargron", - "type": "Person", - "summary": "

Some bio

", - "publicKey": { +{ + "type": "Update", + "object": { + "url": "http://mastodon.example.org/@gargron", + "type": "Person", + "summary": "

Some bio

", + "publicKey": { "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gs3VnQf6am3R+CeBV4H\nlfI1HZTNRIBHgvFszRZkCERbRgEWMu+P+I6/7GJC5H5jhVQ60z4MmXcyHOGmYMK/\n5XyuHQz7V2Ssu1AxLfRN5Biq1ayb0+DT/E7QxNXDJPqSTnstZ6C7zKH/uAETqg3l\nBonjCQWyds+IYbQYxf5Sp3yhvQ80lMwHML3DaNCMlXWLoOnrOX5/yK5+dedesg2\n/HIvGk+HEt36vm6hoH7bwPuEkgA++ACqwjXRe5Mta7i3eilHxFaF8XIrJFARV0t\nqOu4GID/jG6oA+swIWndGrtR2QRJIt9QIBFfK3HG5M0koZbY1eTqwNFRHFL3xaD\nUQIDAQAB\n-----END PUBLIC KEY-----\n", "owner": "http://mastodon.example.org/users/gargron", "id": "http://mastodon.example.org/users/gargron#main-key" @@ -20,7 +20,27 @@ "endpoints": { "sharedInbox": "http://mastodon.example.org/inbox" }, - "icon":{"type":"Image","mediaType":"image/jpeg","url":"https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"},"image":{"type":"Image","mediaType":"image/png","url":"https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"} + "attachment": [{ + "type": "PropertyValue", + "name": "foo", + "value": "updated" + }, + { + "type": "PropertyValue", + "name": "foo1", + "value": "updated" + } + ], + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" + }, + "image": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" + } }, "id": "http://mastodon.example.org/users/gargron#updates/1519563538", "actor": "http://mastodon.example.org/users/gargron", diff --git a/test/fixtures/tesla_mock/admin@mastdon.example.org.json b/test/fixtures/tesla_mock/admin@mastdon.example.org.json index c297e4349..8159dc20a 100644 --- a/test/fixtures/tesla_mock/admin@mastdon.example.org.json +++ b/test/fixtures/tesla_mock/admin@mastdon.example.org.json @@ -1 +1,54 @@ -{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":"as:movedTo","Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji"}],"id":"http://mastodon.example.org/users/admin","type":"Person","following":"http://mastodon.example.org/users/admin/following","followers":"http://mastodon.example.org/users/admin/followers","inbox":"http://mastodon.example.org/users/admin/inbox","outbox":"http://mastodon.example.org/users/admin/outbox","preferredUsername":"admin","name":null,"summary":"\u003cp\u003e\u003c/p\u003e","url":"http://mastodon.example.org/@admin","manuallyApprovesFollowers":false,"publicKey":{"id":"http://mastodon.example.org/users/admin#main-key","owner":"http://mastodon.example.org/users/admin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n"},"endpoints":{"sharedInbox":"http://mastodon.example.org/inbox"},"icon":{"type":"Image","mediaType":"image/jpeg","url":"https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"},"image":{"type":"Image","mediaType":"image/png","url":"https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"}} +{ + "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "sensitive": "as:sensitive", + "movedTo": "as:movedTo", + "Hashtag": "as:Hashtag", + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji" + }], + "id": "http://mastodon.example.org/users/admin", + "type": "Person", + "following": "http://mastodon.example.org/users/admin/following", + "followers": "http://mastodon.example.org/users/admin/followers", + "inbox": "http://mastodon.example.org/users/admin/inbox", + "outbox": "http://mastodon.example.org/users/admin/outbox", + "preferredUsername": "admin", + "name": null, + "summary": "\u003cp\u003e\u003c/p\u003e", + "url": "http://mastodon.example.org/@admin", + "manuallyApprovesFollowers": false, + "publicKey": { + "id": "http://mastodon.example.org/users/admin#main-key", + "owner": "http://mastodon.example.org/users/admin", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n" + }, + "attachment": [{ + "type": "PropertyValue", + "name": "foo", + "value": "bar" + }, + { + "type": "PropertyValue", + "name": "foo1", + "value": "bar1" + } + ], + "endpoints": { + "sharedInbox": "http://mastodon.example.org/inbox" + }, + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" + }, + "image": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" + } +} diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 060b91e29..05ec09ec1 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -509,6 +509,42 @@ test "it works for incoming update activities" do assert user.bio == "

Some bio

" end + test "it works with custom profile fields" do + {:ok, activity} = + "test/fixtures/mastodon-post-activity.json" + |> File.read!() + |> Poison.decode!() + |> Transmogrifier.handle_incoming() + + user = User.get_cached_by_ap_id(activity.actor) + + assert user.info.source_data["attachment"] == [ + %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, + %{"name" => "foo1", "type" => "PropertyValue", "value" => "bar1"} + ] + + update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + + object = + update_data["object"] + |> Map.put("actor", user.ap_id) + |> Map.put("id", user.ap_id) + + update_data = + update_data + |> Map.put("actor", user.ap_id) + |> Map.put("object", object) + + {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.info.source_data["attachment"] == [ + %{"name" => "foo", "type" => "PropertyValue", "value" => "updated"}, + %{"name" => "foo1", "type" => "PropertyValue", "value" => "updated"} + ] + end + test "it works for incoming update activities which lock the account" do data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() From 7d6f8a7fd75e5de4e0c9ce208ac9276dcbe044f5 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 29 Jul 2019 19:17:09 +0700 Subject: [PATCH 154/202] Linkify custom fields values in ActivityPub.UserViewx --- lib/pleroma/web/activity_pub/views/user_view.ex | 1 + test/web/activity_pub/views/user_view_test.exs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 7b4bc998b..b2a22478d 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -84,6 +84,7 @@ def render("user.json", %{user: user}) do user.info |> User.Info.fields() |> Enum.map(&Map.put(&1, "type", "PropertyValue")) + |> Enum.map(fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) %{ "id" => user.ap_id, diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 48a522c6c..a2aa52381 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -33,7 +33,11 @@ test "Renders profile fields" do assert %{ "attachment" => [ %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, - %{"name" => "website", "type" => "PropertyValue", "value" => "cofe.my"} + %{ + "name" => "website", + "type" => "PropertyValue", + "value" => "cofe.my" + } ] } = UserView.render("user.json", %{user: user}) end From db3c05f6b4c226733633a409cb1f1a290db4c48b Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 30 Jul 2019 17:22:52 +0700 Subject: [PATCH 155/202] Add configurable account field value length limit --- config/config.exs | 1 + docs/config.md | 1 + lib/pleroma/user/info.ex | 7 ++++- .../update_credentials_test.exs | 31 +++++++++++++++---- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index 109cf6516..21f4861f2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,6 +256,7 @@ user_bio_length: 5000, user_name_length: 100, max_account_fields: 4, + account_field_value_length: 255, external_user_synchronization: true config :pleroma, :markup, diff --git a/docs/config.md b/docs/config.md index ca5da7db1..fbb506093 100644 --- a/docs/config.md +++ b/docs/config.md @@ -133,6 +133,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. * `max_account_fields`: The maximum number of custom fields in the user profile (default: `4`) +* `account_field_value_length`: An account field value maximum length (default: `255`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 98b894223..9e4d381f8 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -308,7 +308,12 @@ def validate_fields(changeset) do end defp valid_field?(%{"name" => name, "value" => value}) do - is_binary(name) && is_binary(value) + value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) + + is_binary(name) && + is_binary(value) && + String.length(name) <= 255 && + String.length(value) <= value_limit end defp valid_field?(_), do: false diff --git a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs index a3eadde16..992a692f0 100644 --- a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs @@ -325,6 +325,26 @@ test "update fields", %{conn: conn} do %{"name" => "link", "value" => "cofe.io"} ] + value_limit = Pleroma.Config.get([:instance, :account_field_value_length]) + + long_str = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join() + + fields = [%{"name" => "foo", "value" => long_str}] + + assert %{"error" => "Invalid request"} == + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) + |> json_response(403) + + fields = [%{"name" => long_str, "value" => "bar"}] + + assert %{"error" => "Invalid request"} == + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) + |> json_response(403) + Pleroma.Config.put([:instance, :max_account_fields], 1) fields = [ @@ -332,12 +352,11 @@ test "update fields", %{conn: conn} do %{"name" => "link", "value" => "cofe.io"} ] - conn = - conn - |> assign(:user, user) - |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) - - assert %{"error" => "Invalid request"} == json_response(conn, 403) + assert %{"error" => "Invalid request"} == + conn + |> assign(:user, user) + |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) + |> json_response(403) end end end From 2c35d4b0b04e58368c51f2828536d295f72839a2 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 1 Aug 2019 15:09:15 +0700 Subject: [PATCH 156/202] Add configurable account field name length limit --- config/config.exs | 1 + docs/config.md | 1 + lib/pleroma/user/info.ex | 3 ++- .../mastodon_api_controller/update_credentials_test.exs | 9 ++++++--- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index 21f4861f2..4fd241e90 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,6 +256,7 @@ user_bio_length: 5000, user_name_length: 100, max_account_fields: 4, + account_field_name_length: 255, account_field_value_length: 255, external_user_synchronization: true diff --git a/docs/config.md b/docs/config.md index fbb506093..6744f5879 100644 --- a/docs/config.md +++ b/docs/config.md @@ -133,6 +133,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. * `max_account_fields`: The maximum number of custom fields in the user profile (default: `4`) +* `account_field_name_length`: An account field name maximum length (default: `255`) * `account_field_value_length`: An account field value maximum length (default: `255`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 9e4d381f8..e54243f06 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -308,11 +308,12 @@ def validate_fields(changeset) do end defp valid_field?(%{"name" => name, "value" => value}) do + name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) is_binary(name) && is_binary(value) && - String.length(name) <= 255 && + String.length(name) <= name_limit && String.length(value) <= value_limit end diff --git a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs index 992a692f0..e75f25d51 100644 --- a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs @@ -325,11 +325,12 @@ test "update fields", %{conn: conn} do %{"name" => "link", "value" => "cofe.io"} ] + name_limit = Pleroma.Config.get([:instance, :account_field_name_length]) value_limit = Pleroma.Config.get([:instance, :account_field_value_length]) - long_str = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join() + long_value = Enum.map(0..value_limit, fn _ -> "x" end) |> Enum.join() - fields = [%{"name" => "foo", "value" => long_str}] + fields = [%{"name" => "foo", "value" => long_value}] assert %{"error" => "Invalid request"} == conn @@ -337,7 +338,9 @@ test "update fields", %{conn: conn} do |> patch("/api/v1/accounts/update_credentials", %{"fields" => fields}) |> json_response(403) - fields = [%{"name" => long_str, "value" => "bar"}] + long_name = Enum.map(0..name_limit, fn _ -> "x" end) |> Enum.join() + + fields = [%{"name" => long_name, "value" => "bar"}] assert %{"error" => "Invalid request"} == conn From f7bbf99caade7f06756e95e3a4e2f0e4d3e76579 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 6 Aug 2019 18:21:25 +0700 Subject: [PATCH 157/202] Use info.fields instead of source_data for remote users --- lib/pleroma/html.ex | 28 +++++++++++++++++++ lib/pleroma/user/info.ex | 6 +++- .../web/activity_pub/transmogrifier.ex | 10 +++++-- .../web/activity_pub/views/user_view.ex | 7 ++++- .../mastodon_api/mastodon_api_controller.ex | 13 ++++----- .../web/mastodon_api/views/account_view.ex | 18 ++++++++---- .../web/twitter_api/views/user_view.ex | 10 ++++++- test/web/activity_pub/transmogrifier_test.exs | 12 ++++---- .../web/activity_pub/views/user_view_test.exs | 17 ++++------- .../update_credentials_test.exs | 9 ++++-- 10 files changed, 91 insertions(+), 39 deletions(-) diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 2fae7281c..bf2000d90 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -280,3 +280,31 @@ def scrub({tag, attributes, children}), do: {tag, attributes, children} def scrub({_tag, children}), do: children def scrub(text), do: text end + +defmodule Pleroma.HTML.Scrubber.LinksOnly do + @moduledoc """ + An HTML scrubbing policy which limits to links only. + """ + + @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) + + require HtmlSanitizeEx.Scrubber.Meta + alias HtmlSanitizeEx.Scrubber.Meta + + Meta.remove_cdata_sections_before_scrub() + Meta.strip_comments() + + # links + Meta.allow_tag_with_uri_attributes("a", ["href"], @valid_schemes) + + Meta.allow_tag_with_this_attribute_values("a", "rel", [ + "tag", + "nofollow", + "noopener", + "noreferrer", + "me" + ]) + + Meta.allow_tag_with_these_attributes("a", ["name", "title"]) + Meta.strip_everything_not_covered() +end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index e54243f06..ada9fb689 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -50,6 +50,7 @@ defmodule Pleroma.User.Info do field(:emoji, {:array, :map}, default: []) field(:pleroma_settings_store, :map, default: %{}) field(:fields, {:array, :map}, default: []) + field(:raw_fields, {:array, :map}, default: []) field(:notification_settings, :map, default: %{ @@ -270,8 +271,10 @@ def user_upgrade(info, params) do :follower_count, :following_count, :hide_follows, + :fields, :hide_followers ]) + |> validate_fields() end def profile_update(info, params) do @@ -288,6 +291,7 @@ def profile_update(info, params) do :show_role, :skip_thread_containment, :fields, + :raw_fields, :pleroma_settings_store ]) |> validate_fields() @@ -415,7 +419,7 @@ def remove_reblog_mute(info, ap_id) do # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # For example: [{"name": "Pronoun", "value": "she/her"}, …] - def fields(%{source_data: %{"attachment" => attachment}}) do + def fields(%{fields: [], source_data: %{"attachment" => attachment}}) do attachment |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 225c34875..2be2e3294 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -598,13 +598,17 @@ def handle_incoming( banner = new_user_data[:info][:banner] locked = new_user_data[:info][:locked] || false - attachment = get_in(new_user_data, [:info, "source_data", "attachment"]) + attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || [] + + fields = + attachment + |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) + |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) update_data = new_user_data |> Map.take([:name, :bio, :avatar]) - |> Map.put(:info, %{banner: banner, locked: locked}) - |> Map.put(:info, %{"banner" => banner, "locked" => locked, "source_data" => source_data}) + |> Map.put(:info, %{banner: banner, locked: locked, fields: fields}) actor |> User.upgrade_changeset(update_data) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index b2a22478d..7be734b26 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -83,8 +83,13 @@ def render("user.json", %{user: user}) do fields = user.info |> User.Info.fields() + |> Enum.map(fn %{"name" => name, "value" => value} -> + %{ + "name" => Pleroma.HTML.strip_tags(name), + "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) + } + end) |> Enum.map(&Map.put(&1, "type", "PropertyValue")) - |> Enum.map(fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) %{ "id" => user.ap_id, diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e79a02caa..e8fac8880 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -137,7 +137,9 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") user_info_emojis = - ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + user.info + |> Map.get(:emoji, []) + |> Enum.concat(Formatter.get_emoji_map(emojis_text)) |> Enum.dedup() info_params = @@ -157,16 +159,11 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do end) |> add_if_present(params, "default_scope", :default_scope) |> add_if_present(params, "fields", :fields, fn fields -> - fields = - Enum.map(fields, fn field -> - %{ - "name" => Formatter.html_escape(field["name"], "text/plain"), - "value" => Formatter.html_escape(field["value"], "text/plain") - } - end) + fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) {:ok, fields} end) + |> add_if_present(params, "fields", :raw_fields) |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value -> {:ok, Map.merge(user.info.pleroma_settings_store, value)} end) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index d2f3986ff..a2297a8e8 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -93,11 +93,19 @@ defp do_render("account.json", %{user: user} = opts) do } end) - fields = User.Info.fields(user.info) - fields_html = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end) + fields = + user.info + |> User.Info.fields() + |> Enum.map(fn %{"name" => name, "value" => value} -> + %{ + "name" => Pleroma.HTML.strip_tags(name), + "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) + } + end) + + raw_fields = Map.get(user.info, :raw_fields, []) bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for])) - relationship = render("relationship.json", %{user: opts[:for], target: user}) %{ @@ -117,12 +125,12 @@ defp do_render("account.json", %{user: user} = opts) do header: header, header_static: header, emojis: emojis, - fields: fields_html, + fields: fields, bot: bot, source: %{ note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, - fields: fields, + fields: raw_fields, pleroma: %{} }, diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 3681773be..8a7d2fc72 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -74,7 +74,15 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do |> HTML.filter_tags(User.html_filter_policy(for_user)) |> Formatter.emojify(emoji) - fields = User.Info.fields(user.info) + fields = + user.info + |> User.Info.fields() + |> Enum.map(fn %{"name" => name, "value" => value} -> + %{ + "name" => Pleroma.HTML.strip_tags(name), + "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) + } + end) data = %{ diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 05ec09ec1..7e2c8769d 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -518,9 +518,9 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(activity.actor) - assert user.info.source_data["attachment"] == [ - %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, - %{"name" => "foo1", "type" => "PropertyValue", "value" => "bar1"} + assert User.Info.fields(user.info) == [ + %{"name" => "foo", "value" => "bar"}, + %{"name" => "foo1", "value" => "bar1"} ] update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() @@ -539,9 +539,9 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(user.ap_id) - assert user.info.source_data["attachment"] == [ - %{"name" => "foo", "type" => "PropertyValue", "value" => "updated"}, - %{"name" => "foo1", "type" => "PropertyValue", "value" => "updated"} + assert User.Info.fields(user.info) == [ + %{"name" => "foo", "value" => "updated"}, + %{"name" => "foo1", "value" => "updated"} ] end diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index a2aa52381..fb7fd9e79 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -24,21 +24,16 @@ test "Renders a user, including the public key" do test "Renders profile fields" do fields = [ - %{"name" => "foo", "value" => "bar"}, - %{"name" => "website", "value" => "cofe.my"} + %{"name" => "foo", "value" => "bar"} ] - user = insert(:user, info: %{fields: fields}) + {:ok, user} = + insert(:user) + |> User.upgrade_changeset(%{info: %{fields: fields}}) + |> User.update_and_set_cache() assert %{ - "attachment" => [ - %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, - %{ - "name" => "website", - "type" => "PropertyValue", - "value" => "cofe.my" - } - ] + "attachment" => [%{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}] } = UserView.render("user.json", %{user: user}) end diff --git a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs index e75f25d51..dd443495b 100644 --- a/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller/update_credentials_test.exs @@ -305,7 +305,7 @@ test "update fields", %{conn: conn} do user = insert(:user) fields = [ - %{"name" => "foo", "value" => "bar"}, + %{"name" => "foo", "value" => ""}, %{"name" => "link", "value" => "cofe.io"} ] @@ -316,12 +316,15 @@ test "update fields", %{conn: conn} do |> json_response(200) assert account["fields"] == [ - %{"name" => "<b>foo<b>", "value" => "<i>bar</i>"}, + %{"name" => "foo", "value" => "bar"}, %{"name" => "link", "value" => "cofe.io"} ] assert account["source"]["fields"] == [ - %{"name" => "<b>foo<b>", "value" => "<i>bar</i>"}, + %{ + "name" => "foo", + "value" => "" + }, %{"name" => "link", "value" => "cofe.io"} ] From e457fcc47971df6c76c3da096e6b45c2972e4029 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 7 Aug 2019 18:14:22 +0700 Subject: [PATCH 158/202] Add `:max_remote_account_fields` config option --- config/config.exs | 1 + docs/config.md | 1 + lib/pleroma/user.ex | 4 ++-- lib/pleroma/user/info.ex | 11 +++++++---- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +++++++ lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- test/web/activity_pub/transmogrifier_test.exs | 18 ++++++++++++++++++ 7 files changed, 37 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index 4fd241e90..3937f7e70 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,6 +256,7 @@ user_bio_length: 5000, user_name_length: 100, max_account_fields: 4, + max_remote_account_fields: 10, account_field_name_length: 255, account_field_value_length: 255, external_user_synchronization: true diff --git a/docs/config.md b/docs/config.md index 6744f5879..b4bdbd078 100644 --- a/docs/config.md +++ b/docs/config.md @@ -133,6 +133,7 @@ config :pleroma, Pleroma.Emails.Mailer, * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. * `max_account_fields`: The maximum number of custom fields in the user profile (default: `4`) +* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `10`) * `account_field_name_length`: An account field name maximum length (default: `255`) * `account_field_value_length`: An account field value maximum length (default: `255`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b67743846..faa1e3d50 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -199,12 +199,12 @@ def update_changeset(struct, params \\ %{}) do |> validate_length(:name, min: 1, max: name_limit) end - def upgrade_changeset(struct, params \\ %{}) do + def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now()) - info_cng = User.Info.user_upgrade(struct.info, params[:info]) + info_cng = User.Info.user_upgrade(struct.info, params[:info], remote?) struct |> cast(params, [ diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ada9fb689..47e7df911 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -256,11 +256,13 @@ def remote_user_creation(info, params) do :hide_followers, :hide_follows, :follower_count, + :fields, :following_count ]) + |> validate_fields(true) end - def user_upgrade(info, params) do + def user_upgrade(info, params, remote? \\ false) do info |> cast(params, [ :ap_enabled, @@ -274,7 +276,7 @@ def user_upgrade(info, params) do :fields, :hide_followers ]) - |> validate_fields() + |> validate_fields(remote?) end def profile_update(info, params) do @@ -297,8 +299,9 @@ def profile_update(info, params) do |> validate_fields() end - def validate_fields(changeset) do - limit = Pleroma.Config.get([:instance, :max_account_fields], 0) + def validate_fields(changeset, remote? \\ false) do + limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields + limit = Pleroma.Config.get([:instance, limit_name], 0) changeset |> validate_length(:fields, max: limit) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index cf55c9520..7bb7740bf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1016,6 +1016,12 @@ defp object_to_user_data(data) do "url" => [%{"href" => data["image"]["url"]}] } + fields = + data + |> Map.get("attachment", []) + |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) + |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + locked = data["manuallyApprovesFollowers"] || false data = Transmogrifier.maybe_fix_user_object(data) @@ -1025,6 +1031,7 @@ defp object_to_user_data(data) do ap_enabled: true, source_data: data, banner: banner, + fields: fields, locked: locked }, avatar: avatar, diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 2be2e3294..36340a3a1 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -611,7 +611,7 @@ def handle_incoming( |> Map.put(:info, %{banner: banner, locked: locked, fields: fields}) actor - |> User.upgrade_changeset(update_data) + |> User.upgrade_changeset(update_data, true) |> User.update_and_set_cache() ActivityPub.update(%{ diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 7e2c8769d..d8fbcd628 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -539,6 +539,24 @@ test "it works with custom profile fields" do user = User.get_cached_by_ap_id(user.ap_id) + assert User.Info.fields(user.info) == [ + %{"name" => "foo", "value" => "updated"}, + %{"name" => "foo1", "value" => "updated"} + ] + + Pleroma.Config.put([:instance, :max_remote_account_fields], 2) + + update_data = + put_in(update_data, ["object", "attachment"], [ + %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, + %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"}, + %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"} + ]) + + {:ok, _} = Transmogrifier.handle_incoming(update_data) + + user = User.get_cached_by_ap_id(user.ap_id) + assert User.Info.fields(user.info) == [ %{"name" => "foo", "value" => "updated"}, %{"name" => "foo1", "value" => "updated"} From 672fcbc7b716f18346a17845d05c286b45dca5f3 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 7 Aug 2019 18:48:05 +0700 Subject: [PATCH 159/202] Limit custom fields for old remote users --- lib/pleroma/user/info.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 47e7df911..45a39924b 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -423,9 +423,12 @@ def remove_reblog_mute(info, ap_id) do # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # For example: [{"name": "Pronoun", "value": "she/her"}, …] def fields(%{fields: [], source_data: %{"attachment" => attachment}}) do + limit = Pleroma.Config.get([:instance, :max_remote_account_fields], 0) + attachment |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) + |> Enum.take(limit) end def fields(%{fields: fields}), do: fields From a2e1db56323d0f306ee42a1f58471eb55c8c1e68 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 8 Aug 2019 13:20:35 +0700 Subject: [PATCH 160/202] Increase max account fields limits --- config/config.exs | 4 ++-- docs/config.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index 3937f7e70..7279b43b7 100644 --- a/config/config.exs +++ b/config/config.exs @@ -255,8 +255,8 @@ dynamic_configuration: false, user_bio_length: 5000, user_name_length: 100, - max_account_fields: 4, - max_remote_account_fields: 10, + max_account_fields: 10, + max_remote_account_fields: 20, account_field_name_length: 255, account_field_value_length: 255, external_user_synchronization: true diff --git a/docs/config.md b/docs/config.md index b4bdbd078..7e4e96db0 100644 --- a/docs/config.md +++ b/docs/config.md @@ -132,8 +132,8 @@ config :pleroma, Pleroma.Emails.Mailer, * `skip_thread_containment`: Skip filter out broken threads. The default is `false`. * `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`. * `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api. -* `max_account_fields`: The maximum number of custom fields in the user profile (default: `4`) -* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `10`) +* `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`) +* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`) * `account_field_name_length`: An account field name maximum length (default: `255`) * `account_field_value_length`: An account field value maximum length (default: `255`) * `external_user_synchronization`: Enabling following/followers counters synchronization for external users. From 4b7f1c6995ca49c782e3e29d14245f18d4d11430 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 14 Aug 2019 20:46:05 +0700 Subject: [PATCH 161/202] Improve digest email template --- lib/mix/tasks/pleroma/digest.ex | 12 +- lib/pleroma/emails/user_email.ex | 17 + .../web/templates/email/digest.html.eex | 581 +++++++++++++++++- lib/pleroma/web/views/email_view.ex | 10 + test/mix/tasks/pleroma.digest_test.exs | 2 +- 5 files changed, 602 insertions(+), 20 deletions(-) diff --git a/lib/mix/tasks/pleroma/digest.ex b/lib/mix/tasks/pleroma/digest.ex index 81c207e10..430116a50 100644 --- a/lib/mix/tasks/pleroma/digest.ex +++ b/lib/mix/tasks/pleroma/digest.ex @@ -27,7 +27,15 @@ def run(["test", nickname | opts]) do patched_user = %{user | last_digest_emailed_at: last_digest_emailed_at} - _user = Pleroma.DigestEmailWorker.perform(patched_user) - Mix.shell().info("Digest email have been sent to #{nickname} (#{user.email})") + with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(patched_user) do + {:ok, _} = Pleroma.Emails.Mailer.deliver(email) + + Mix.shell().info("Digest email have been sent to #{nickname} (#{user.email})") + else + _ -> + Mix.shell().info( + "Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}" + ) + end end end diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 49046bb8b..bf6b811b1 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -123,6 +123,11 @@ def digest_email(user) do end) with [_ | _] = mentions <- new_notifications.mentions do + mentions = + Enum.map(mentions, fn mention -> + update_in(mention.object.data["content"], &format_links/1) + end) + html_data = %{ instance: instance_name(), user: user, @@ -131,17 +136,29 @@ def digest_email(user) do unsubscribe_link: unsubscribe_url(user, "digest") } + logo_path = Path.join(:code.priv_dir(:pleroma), "static/static/logo.png") + new() |> to(recipient(user)) |> from(sender()) |> subject("Your digest from #{instance_name()}") + |> put_layout(false) |> render_body("digest.html", html_data) + |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline)) else _ -> nil end end + defp format_links(str) do + re = ~r//iU + + String.replace(str, re, fn link -> + String.replace(link, "Hey <%= @user.nickname %>, here is what you've missed! + -

New Mentions:

-
    -<%= for %{data: mention, object: object, from: from} <- @mentions do %> -
  • <%= link from.nickname, to: mention.activity.actor %>: <%= raw object.data["content"] %>
  • -<% end %> -
+ -<%= if @followers != [] do %> -

<%= length(@followers) %> New Followers:

-
    -<%= for %{data: follow, from: from} <- @followers do %> -
  • <%= link from.nickname, to: follow.activity.actor %>
  • -<% end %> -
-<% end %> + + + + + + + + <%= @email.subject %>< + + + + + + + + + + + + + + + + + + + diff --git a/lib/pleroma/web/views/email_view.ex b/lib/pleroma/web/views/email_view.ex index b63eb162c..b506a234b 100644 --- a/lib/pleroma/web/views/email_view.ex +++ b/lib/pleroma/web/views/email_view.ex @@ -2,4 +2,14 @@ defmodule Pleroma.Web.EmailView do use Pleroma.Web, :view import Phoenix.HTML import Phoenix.HTML.Link + + def avatar_url(user) do + Pleroma.User.avatar_url(user) + end + + def format_date(date) when is_binary(date) do + date + |> Timex.parse!("{ISO:Extended:Z}") + |> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}") + end end diff --git a/test/mix/tasks/pleroma.digest_test.exs b/test/mix/tasks/pleroma.digest_test.exs index 595f64ed7..4bfa1fb93 100644 --- a/test/mix/tasks/pleroma.digest_test.exs +++ b/test/mix/tasks/pleroma.digest_test.exs @@ -44,7 +44,7 @@ test "Sends digest to the given user" do assert_email_sent( to: {user2.name, user2.email}, - html_body: ~r/new mentions:/i + html_body: ~r/here is what you've missed!/i ) end end From df81abb68c46e36dfb2af7aab77e0e57a1a1eb28 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 14 Aug 2019 15:55:43 +0200 Subject: [PATCH 162/202] Conversations: Use correct oauth paths for extended api. --- lib/pleroma/web/router.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9759268f9..1eb6f7b9d 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -263,9 +263,13 @@ defmodule Pleroma.Web.Router do pipe_through(:authenticated_api) scope [] do - pipe_through(:oauth_write) + pipe_through(:oauth_read) get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) get("/conversations/:id", PleromaAPIController, :conversation) + end + + scope [] do + pipe_through(:oauth_write) patch("/conversations/:id", PleromaAPIController, :update_conversation) end end From f73212b2a36deef631716f3c8a80d7da11cec759 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 14 Aug 2019 15:56:15 +0200 Subject: [PATCH 163/202] Conversation: Render new participation on update. --- lib/pleroma/web/pleroma_api/pleroma_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index b5c3d2728..6d74d418e 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -66,7 +66,7 @@ def update_conversation( |> Participation.get() with true <- user.id == participation.user_id, - {:ok, _} <- Participation.set_recipients(participation, recipients) do + {:ok, participation} <- Participation.set_recipients(participation, recipients) do conn |> put_view(ConversationView) |> render("participation.json", %{participation: participation, for: user}) From c9970feee20f25375223e5f4a32bdbcff7b98607 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 14 Aug 2019 21:03:25 +0700 Subject: [PATCH 164/202] Fix compatibility with Elixir 1.8 --- lib/pleroma/emails/user_email.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index bf6b811b1..3b5e64019 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -154,7 +154,7 @@ def digest_email(user) do defp format_links(str) do re = ~r//iU - String.replace(str, re, fn link -> + Regex.replace(re, str, fn link -> String.replace(link, " Date: Wed, 14 Aug 2019 17:05:21 +0300 Subject: [PATCH 165/202] Switch to pre-1.8 version of tzdata. tzdata 1.0.0 requires Elixir 1.8.0, but we target 1.7. Fortunately tzdata issues bugfix releases for pre-1.8.0 version. --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 334fabb33..3170d6f2d 100644 --- a/mix.exs +++ b/mix.exs @@ -95,7 +95,7 @@ defp oauth_deps do defp deps do [ {:phoenix, "~> 1.4.8"}, - {:tzdata, "~> 1.0"}, + {:tzdata, "~> 0.5.21"}, {:plug_cowboy, "~> 2.0"}, {:phoenix_pubsub, "~> 1.1"}, {:phoenix_ecto, "~> 4.0"}, diff --git a/mix.lock b/mix.lock index f8ee80c83..2639e96e9 100644 --- a/mix.lock +++ b/mix.lock @@ -87,7 +87,7 @@ "tesla": {:hex, :tesla, "1.2.1", "864783cc27f71dd8c8969163704752476cec0f3a51eb3b06393b3971dc9733ff", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "tzdata": {:hex, :tzdata, "0.5.21", "8cbf3607fcce69636c672d5be2bbb08687fe26639a62bdcc283d267277db7cf0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "ueberauth": {:hex, :ueberauth, "0.6.1", "9e90d3337dddf38b1ca2753aca9b1e53d8a52b890191cdc55240247c89230412", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"}, From d3af9e19edb32e04d101e50ae2868ba6f66cbed9 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 14 Aug 2019 17:01:11 +0200 Subject: [PATCH 166/202] Conversations: Load relations in one query. --- lib/pleroma/conversation/participation.ex | 16 +++++++++++++--- .../web/pleroma_api/pleroma_api_controller.ex | 4 +--- test/conversation/participation_test.exs | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index d17b6f7c5..ea5b9fe17 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -94,10 +94,20 @@ def for_user_with_last_activity_id(user, params \\ %{}) do |> Enum.filter(& &1.last_activity_id) end - def get(nil), do: nil + def get(_, _ \\ []) + def get(nil, _), do: nil - def get(id) do - Repo.get(__MODULE__, id) + def get(id, params) do + query = + if preload = params[:preload] do + from(p in __MODULE__, + preload: ^preload + ) + else + __MODULE__ + end + + Repo.get(query, id) end def set_recipients(participation, user_ids) do diff --git a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex index 6d74d418e..b6d2bf86b 100644 --- a/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/pleroma_api_controller.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7] alias Pleroma.Conversation.Participation - alias Pleroma.Repo alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.StatusView @@ -34,8 +33,7 @@ def conversation_statuses( participation = participation_id - |> Participation.get() - |> Repo.preload(:conversation) + |> Participation.get(preload: [:conversation]) if user.id == participation.user_id do activities = diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 7958e8e89..a27167d42 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -8,6 +8,20 @@ defmodule Pleroma.Conversation.ParticipationTest do alias Pleroma.Conversation.Participation alias Pleroma.Web.CommonAPI + test "getting a participation will also preload things" do + user = insert(:user) + other_user = insert(:user) + + {:ok, _activity} = + CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"}) + + [participation] = Participation.for_user(user) + + participation = Participation.get(participation.id, preload: [:conversation]) + + assert %Pleroma.Conversation{} = participation.conversation + end + test "for a new conversation, it sets the recipents of the participation" do user = insert(:user) other_user = insert(:user) From 51bdf0cab6dc96bfd48a6d98d9f21584b42c0e44 Mon Sep 17 00:00:00 2001 From: stwf Date: Wed, 14 Aug 2019 11:55:17 -0400 Subject: [PATCH 167/202] use default child_specs --- lib/pleroma/application.ex | 185 ++++++-------------- lib/pleroma/captcha/captcha.ex | 2 +- lib/pleroma/config/transfer_task.ex | 2 +- lib/pleroma/emoji.ex | 2 +- lib/pleroma/flake_id.ex | 2 +- lib/pleroma/gopher/server.ex | 2 +- lib/pleroma/scheduled_activity_worker.ex | 2 +- lib/pleroma/stats.ex | 4 +- lib/pleroma/web/chat_channel.ex | 4 +- lib/pleroma/web/federator/retry_queue.ex | 2 +- lib/pleroma/web/oauth/token/clean_worker.ex | 3 +- lib/pleroma/web/streamer.ex | 2 +- test/config/transfer_task_test.exs | 4 +- 13 files changed, 73 insertions(+), 143 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 00b06f723..3bb0718e4 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -3,11 +3,14 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Application do + import Cachex.Spec use Application @name Mix.Project.config()[:name] @version Mix.Project.config()[:version] @repository Mix.Project.config()[:source_url] + @env Mix.env() + def name, do: @name def version, do: @version def named_version, do: @name <> " " <> @version @@ -21,116 +24,25 @@ def user_agent do # See http://elixir-lang.org/docs/stable/elixir/Application.html # for more information on OTP Applications def start(_type, _args) do - import Cachex.Spec - Pleroma.Config.DeprecationWarnings.warn() setup_instrumenters() # Define workers and child supervisors to be supervised children = [ - # Start the Ecto repository - %{id: Pleroma.Repo, start: {Pleroma.Repo, :start_link, []}, type: :supervisor}, - %{id: Pleroma.Config.TransferTask, start: {Pleroma.Config.TransferTask, :start_link, []}}, - %{id: Pleroma.Emoji, start: {Pleroma.Emoji, :start_link, []}}, - %{id: Pleroma.Captcha, start: {Pleroma.Captcha, :start_link, []}}, - %{ - id: :cachex_used_captcha_cache, - start: - {Cachex, :start_link, - [ - :used_captcha_cache, - [ - ttl_interval: - :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])) - ] - ]} - }, - %{ - id: :cachex_user, - start: - {Cachex, :start_link, - [ - :user_cache, - [ - default_ttl: 25_000, - ttl_interval: 1000, - limit: 2500 - ] - ]} - }, - %{ - id: :cachex_object, - start: - {Cachex, :start_link, - [ - :object_cache, - [ - default_ttl: 25_000, - ttl_interval: 1000, - limit: 2500 - ] - ]} - }, - %{ - id: :cachex_rich_media, - start: - {Cachex, :start_link, - [ - :rich_media_cache, - [ - default_ttl: :timer.minutes(120), - limit: 5000 - ] - ]} - }, - %{ - id: :cachex_scrubber, - start: - {Cachex, :start_link, - [ - :scrubber_cache, - [ - limit: 2500 - ] - ]} - }, - %{ - id: :cachex_idem, - start: - {Cachex, :start_link, - [ - :idempotency_cache, - [ - expiration: - expiration( - default: :timer.seconds(6 * 60 * 60), - interval: :timer.seconds(60) - ), - limit: 2500 - ] - ]} - }, - %{id: Pleroma.FlakeId, start: {Pleroma.FlakeId, :start_link, []}}, - %{ - id: Pleroma.ScheduledActivityWorker, - start: {Pleroma.ScheduledActivityWorker, :start_link, []} - } + Pleroma.Repo, + Pleroma.Config.TransferTask, + Pleroma.Emoji, + Pleroma.Captcha, + Pleroma.FlakeId, + Pleroma.ScheduledActivityWorker ] ++ + cachex_children() ++ hackney_pool_children() ++ [ - %{ - id: Pleroma.Web.Federator.RetryQueue, - start: {Pleroma.Web.Federator.RetryQueue, :start_link, []} - }, - %{ - id: Pleroma.Web.OAuth.Token.CleanWorker, - start: {Pleroma.Web.OAuth.Token.CleanWorker, :start_link, []} - }, - %{ - id: Pleroma.Stats, - start: {Pleroma.Stats, :start_link, []} - }, + Pleroma.Web.Federator.RetryQueue, + Pleroma.Web.OAuth.Token.CleanWorker, + Pleroma.Stats, %{ id: :web_push_init, start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, @@ -147,16 +59,11 @@ def start(_type, _args) do restart: :temporary } ] ++ - streamer_child() ++ - chat_child() ++ + streamer_child(@env) ++ + chat_child(@env, chat_enabled?()) ++ [ - # Start the endpoint when the application starts - %{ - id: Pleroma.Web.Endpoint, - start: {Pleroma.Web.Endpoint, :start_link, []}, - type: :supervisor - }, - %{id: Pleroma.Gopher.Server, start: {Pleroma.Gopher.Server, :start_link, []}} + Pleroma.Web.Endpoint, + Pleroma.Gopher.Server ] # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html @@ -201,28 +108,46 @@ def enabled_hackney_pools do end end - if Pleroma.Config.get(:env) == :test do - defp streamer_child, do: [] - defp chat_child, do: [] - else - defp streamer_child do - [%{id: Pleroma.Web.Streamer, start: {Pleroma.Web.Streamer, :start_link, []}}] - end - - defp chat_child do - if Pleroma.Config.get([:chat, :enabled]) do - [ - %{ - id: Pleroma.Web.ChatChannel.ChatChannelState, - start: {Pleroma.Web.ChatChannel.ChatChannelState, :start_link, []} - } - ] - else - [] - end - end + defp cachex_children do + [ + build_cachex("used_captcha", ttl_interval: seconds_valid_interval()), + build_cachex("user", default_ttl: 25_000, ttl_interval: 1000, limit: 2500), + build_cachex("object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500), + build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000), + build_cachex("scrubber", limit: 2500), + build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500) + ] end + defp idempotency_expiration, + do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60)) + + defp seconds_valid_interval, + do: :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])) + + defp build_cachex(type, opts), + do: %{ + id: String.to_atom("cachex_" <> type), + start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]}, + type: :worker + } + + defp chat_enabled?, do: Pleroma.Config.get([:chat, :enabled]) + + defp streamer_child(:test), do: [] + + defp streamer_child(_) do + [Pleroma.Web.Streamer] + end + + defp chat_child(:test, _), do: [] + + defp chat_child(_env, true) do + [Pleroma.Web.ChatChannel.ChatChannelState] + end + + defp chat_child(_, _), do: [] + defp hackney_pool_children do for pool <- enabled_hackney_pools() do options = Pleroma.Config.get([:hackney_pools, pool]) diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex index a73b87251..c2765a5b8 100644 --- a/lib/pleroma/captcha/captcha.ex +++ b/lib/pleroma/captcha/captcha.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Captcha do use GenServer @doc false - def start_link do + def start_link(_) do GenServer.start_link(__MODULE__, [], name: __MODULE__) end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 7799b2a78..3214c9951 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Config.TransferTask do use Task alias Pleroma.Web.AdminAPI.Config - def start_link do + def start_link(_) do load_and_update_env() if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Pleroma.Repo) :ignore diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 052501642..66e20f0e4 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -24,7 +24,7 @@ defmodule Pleroma.Emoji do @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] @doc false - def start_link do + def start_link(_) do GenServer.start_link(__MODULE__, [], name: __MODULE__) end diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex index ca0610abc..47d61ca5f 100644 --- a/lib/pleroma/flake_id.ex +++ b/lib/pleroma/flake_id.ex @@ -98,7 +98,7 @@ def dump(value) do def autogenerate, do: get() # -- GenServer API - def start_link do + def start_link(_) do :gen_server.start_link({:local, :flake}, __MODULE__, [], []) end diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index b3319e137..d4e4f3e55 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Gopher.Server do use GenServer require Logger - def start_link do + def start_link(_) do config = Pleroma.Config.get(:gopher, []) ip = Keyword.get(config, :ip, {0, 0, 0, 0}) port = Keyword.get(config, :port, 1234) diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex index 65b38622f..8578cab5e 100644 --- a/lib/pleroma/scheduled_activity_worker.ex +++ b/lib/pleroma/scheduled_activity_worker.ex @@ -16,7 +16,7 @@ defmodule Pleroma.ScheduledActivityWorker do @schedule_interval :timer.minutes(1) - def start_link do + def start_link(_) do GenServer.start_link(__MODULE__, nil) end diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 5b242927b..101effbe4 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -7,7 +7,9 @@ defmodule Pleroma.Stats do alias Pleroma.Repo alias Pleroma.User - def start_link do + use Agent + + def start_link(_) do agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__) spawn(fn -> schedule_update() end) agent diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex index f63f4bda1..b543909f1 100644 --- a/lib/pleroma/web/chat_channel.ex +++ b/lib/pleroma/web/chat_channel.ex @@ -33,9 +33,11 @@ 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 + def start_link(_) do Agent.start_link(fn -> %{max_id: 1, messages: []} end, name: __MODULE__) end diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex index 3db948c2e..9eab8c218 100644 --- a/lib/pleroma/web/federator/retry_queue.ex +++ b/lib/pleroma/web/federator/retry_queue.ex @@ -13,7 +13,7 @@ def init(args) do {:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}} end - def start_link do + def start_link(_) do enabled = if Pleroma.Config.get(:env) == :test, do: true, diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index dca852449..e39a4986a 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do @moduledoc """ The module represents functions to clean an expired oauth tokens. """ + use GenServer # 10 seconds @start_interval 10_000 @@ -18,7 +19,7 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do alias Pleroma.Web.OAuth.Token - def start_link, do: GenServer.start_link(__MODULE__, nil) + def start_link(_), do: GenServer.start_link(__MODULE__, nil) def init(_) do if Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 9ee331030..e66378ceb 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -18,7 +18,7 @@ defmodule Pleroma.Web.Streamer do @keepalive_interval :timer.seconds(30) - def start_link do + def start_link(_) do GenServer.start_link(__MODULE__, %{}, name: __MODULE__) end diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index dbeadbe87..4455a4d47 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -31,7 +31,7 @@ test "transfer config values from db to env" do value: [live: 15, com: 35] }) - Pleroma.Config.TransferTask.start_link() + Pleroma.Config.TransferTask.start_link([]) assert Application.get_env(:pleroma, :test_key) == [live: 2, com: 3] assert Application.get_env(:idna, :test_key) == [live: 15, com: 35] @@ -50,7 +50,7 @@ test "non existing atom" do }) assert ExUnit.CaptureLog.capture_log(fn -> - Pleroma.Config.TransferTask.start_link() + Pleroma.Config.TransferTask.start_link([]) end) =~ "updating env causes error, key: \"undefined_atom_key\", error: %ArgumentError{message: \"argument error\"}" end From 15ef521009f4c232f417ca9164c6be3f4ee4e018 Mon Sep 17 00:00:00 2001 From: stwf Date: Wed, 14 Aug 2019 11:57:50 -0400 Subject: [PATCH 168/202] Isolate OAuth.Token.CleanWorker --- lib/pleroma/application.ex | 9 ++++++++ lib/pleroma/web/oauth/token/clean_worker.ex | 25 ++++++++------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 3bb0718e4..c460a3bc5 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -59,6 +59,7 @@ def start(_type, _args) do restart: :temporary } ] ++ + oauth_cleanup_child(oauth_cleanup_enabled?()) ++ streamer_child(@env) ++ chat_child(@env, chat_enabled?()) ++ [ @@ -134,12 +135,20 @@ defp build_cachex(type, opts), defp chat_enabled?, do: Pleroma.Config.get([:chat, :enabled]) + defp oauth_cleanup_enabled?, + do: Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) + defp streamer_child(:test), do: [] defp streamer_child(_) do [Pleroma.Web.Streamer] end + defp oauth_cleanup_child(true), + do: [Pleroma.Web.OAuth.Token.CleanWorker] + + defp oauth_cleanup_child(_), do: [] + defp chat_child(:test, _), do: [] defp chat_child(_env, true) do diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index e39a4986a..f50098302 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -8,35 +8,28 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do """ use GenServer - # 10 seconds - @start_interval 10_000 + @ten_seconds 10_000 + @one_day 86_400_000 + @interval Pleroma.Config.get( - # 24 hours [:oauth2, :clean_expired_tokens_interval], - 86_400_000 + @one_day ) - @queue :background alias Pleroma.Web.OAuth.Token - def start_link(_), do: GenServer.start_link(__MODULE__, nil) + def start_link(_), do: GenServer.start_link(__MODULE__, %{}) def init(_) do - if Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) do - Process.send_after(self(), :perform, @start_interval) - {:ok, nil} - else - :ignore - end + Process.send_after(self(), :perform, @ten_seconds) + {:ok, nil} end @doc false def handle_info(:perform, state) do + Token.delete_expired_tokens() + Process.send_after(self(), :perform, @interval) - PleromaJobQueue.enqueue(@queue, __MODULE__, [:clean]) {:noreply, state} end - - # Job Worker Callbacks - def perform(:clean), do: Token.delete_expired_tokens() end From 574856ef01fae7ea411ec363929ab9a22d76a65d Mon Sep 17 00:00:00 2001 From: stwf Date: Wed, 14 Aug 2019 11:58:32 -0400 Subject: [PATCH 169/202] streamline Streamer pings --- lib/pleroma/web/streamer.ex | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index e66378ceb..bbaddd852 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -35,28 +35,21 @@ def stream(topic, item) do end def init(args) do - spawn(fn -> - # 30 seconds - Process.sleep(@keepalive_interval) - GenServer.cast(__MODULE__, %{action: :ping}) - end) + Process.send_after(self(), %{action: :ping}, @keepalive_interval) {:ok, args} end - def handle_cast(%{action: :ping}, topics) do - Map.values(topics) + def handle_info(%{action: :ping}, topics) do + topics + |> Map.values() |> List.flatten() |> Enum.each(fn socket -> Logger.debug("Sending keepalive ping") send(socket.transport_pid, {:text, ""}) end) - spawn(fn -> - # 30 seconds - Process.sleep(@keepalive_interval) - GenServer.cast(__MODULE__, %{action: :ping}) - end) + Process.send_after(self(), %{action: :ping}, @keepalive_interval) {:noreply, topics} end From d81f63845a71e5cc60d95007ecaa2aea52a90422 Mon Sep 17 00:00:00 2001 From: stwf Date: Wed, 14 Aug 2019 11:59:33 -0400 Subject: [PATCH 170/202] Implement Pleroma.Stats as GenServer --- lib/pleroma/stats.ex | 60 +++++++++++++------ .../mastodon_api_controller_test.exs | 4 +- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 101effbe4..a3b8a4d66 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -7,33 +7,56 @@ defmodule Pleroma.Stats do alias Pleroma.Repo alias Pleroma.User - use Agent + use GenServer + + @interval 1000 * 60 * 60 def start_link(_) do - agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__) - spawn(fn -> schedule_update() end) - agent + GenServer.start_link(__MODULE__, initial_data(), name: __MODULE__) + end + + def force_update do + GenServer.call(__MODULE__, :force_update) end def get_stats do - Agent.get(__MODULE__, fn {_, stats} -> stats end) + %{stats: stats} = GenServer.call(__MODULE__, :get_state) + + stats end def get_peers do - Agent.get(__MODULE__, fn {peers, _} -> peers end) + %{peers: peers} = GenServer.call(__MODULE__, :get_state) + + peers end - def schedule_update do - spawn(fn -> - # 1 hour - Process.sleep(1000 * 60 * 60) - schedule_update() - end) - - update_stats() + def init(args) do + Process.send_after(self(), :run_update, @interval) + {:ok, args} end - def update_stats do + def handle_call(:force_update, _from, _state) do + new_stats = get_stat_data() + {:reply, new_stats, new_stats} + end + + def handle_call(:get_state, _from, state) do + {:reply, state, state} + end + + def handle_info(:run_update, _state) do + new_stats = get_stat_data() + + Process.send_after(self(), :run_update, @interval) + {:noreply, new_stats} + end + + defp initial_data do + %{peers: [], stats: %{}} + end + + defp get_stat_data do peers = from( u in User, @@ -54,8 +77,9 @@ def update_stats do user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) - Agent.update(__MODULE__, fn _ -> - {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}} - end) + %{ + peers: peers, + stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count} + } end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 2febe8b3a..112e272f9 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2624,7 +2624,7 @@ test "get instance stats", %{conn: conn} do |> Changeset.put_embed(:info, info_change) |> User.update_and_set_cache() - Pleroma.Stats.update_stats() + Pleroma.Stats.force_update() conn = get(conn, "/api/v1/instance") @@ -2642,7 +2642,7 @@ test "get peers", %{conn: conn} do insert(:user, %{local: false, nickname: "u@peer1.com"}) insert(:user, %{local: false, nickname: "u@peer2.com"}) - Pleroma.Stats.update_stats() + Pleroma.Stats.force_update() conn = get(conn, "/api/v1/instance/peers") From c43152f6c17a287a9fe4f2556ca20a140ea30248 Mon Sep 17 00:00:00 2001 From: stwf Date: Wed, 14 Aug 2019 14:01:11 -0400 Subject: [PATCH 171/202] fix formatting --- lib/pleroma/application.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index c460a3bc5..aa673188f 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -121,17 +121,17 @@ defp cachex_children do end defp idempotency_expiration, - do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60)) + do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60)) defp seconds_valid_interval, - do: :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])) + do: :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])) defp build_cachex(type, opts), - do: %{ - id: String.to_atom("cachex_" <> type), - start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]}, - type: :worker - } + do: %{ + id: String.to_atom("cachex_" <> type), + start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]}, + type: :worker + } defp chat_enabled?, do: Pleroma.Config.get([:chat, :enabled]) @@ -145,7 +145,7 @@ defp streamer_child(_) do end defp oauth_cleanup_child(true), - do: [Pleroma.Web.OAuth.Token.CleanWorker] + do: [Pleroma.Web.OAuth.Token.CleanWorker] defp oauth_cleanup_child(_), do: [] From 626e094589689681845d8057f8abe6ab3cd52f69 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Aug 2019 18:53:18 +0000 Subject: [PATCH 172/202] MRF: fix up unserializable option lists in describe implementations --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex | 3 ++- lib/pleroma/web/activity_pub/mrf/reject_non_public.ex | 3 ++- lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 358287096..835dbc14b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. - Report email not being sent to admins when the reporter is a remote user - MRF: ensure that subdomain_match calls are case-insensitive +- MRF: fix use of unserializable keyword lists in describe() implementations ### Added - **Breaking:** MRF describe API, which adds support for exposing configuration information about MRF policies to NodeInfo. diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index 9863454fa..b3c742954 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -92,5 +92,6 @@ def filter(%{"type" => "Create"} = message) do def filter(message), do: {:ok, message} @impl true - def describe, do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}} + def describe, + do: {:ok, %{mrf_hellthread: Pleroma.Config.get(:mrf_hellthread) |> Enum.into(%{})}} end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index 0ae9397ed..5a809a321 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -46,5 +46,6 @@ def filter(%{"type" => "Create"} = object) do def filter(object), do: {:ok, object} @impl true - def describe, do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}} + def describe, + do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}} end diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index 74da8d57e..4eaea00d8 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -32,5 +32,6 @@ def filter(%{"type" => message_type} = message) do def filter(message), do: {:ok, message} - def describe, do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary)}} + def describe, + do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}} end From 5bb418a90d9efb1fa889028080c5de3a929ff2cc Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Aug 2019 19:00:48 +0000 Subject: [PATCH 173/202] activitypub: publisher: add (request-target) to http signature when POSTing --- CHANGELOG.md | 1 + lib/pleroma/web/activity_pub/publisher.ex | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 358287096..5a6150d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Rich Media: The crawled URL is now spliced into the rich media data. - ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification. - ActivityPub S2S: remote user deletions now work the same as local user deletions. +- ActivityPub S2S: POST requests are now signed with `(request-target)` pseudo-header. - Not being able to access the Mastodon FE login page on private instances - Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 46edab0bd..987a25377 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -46,7 +46,9 @@ def is_representable?(%Activity{} = activity) do """ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do Logger.info("Federating #{id} to #{inbox}") - host = URI.parse(inbox).host + uri = URI.parse(inbox) + host = uri.host + path = uri.path digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) @@ -56,6 +58,7 @@ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = pa signature = Pleroma.Signature.sign(actor, %{ + "(request-target)": "post #{path}", host: host, "content-length": byte_size(json), digest: digest, From 1754f8ce6d9ee896a57961a354001b713c620cd5 Mon Sep 17 00:00:00 2001 From: kaniini Date: Wed, 14 Aug 2019 19:05:44 +0000 Subject: [PATCH 174/202] Apply suggestion to lib/pleroma/web/activity_pub/publisher.ex --- lib/pleroma/web/activity_pub/publisher.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 987a25377..262529b84 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -46,9 +46,7 @@ def is_representable?(%Activity{} = activity) do """ def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do Logger.info("Federating #{id} to #{inbox}") - uri = URI.parse(inbox) - host = uri.host - path = uri.path + %{host: host, path: path} = URI.parse(inbox) digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) From a6a814420ded3973b271d04b29b4d6ad24b6bdf7 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 14 Aug 2019 22:48:44 +0200 Subject: [PATCH 175/202] html.ex: Allow sub and sup elements by default Closes: https://git.pleroma.social/pleroma/pleroma/issues/1191 --- lib/pleroma/html.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 2fae7281c..06e60cba3 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -203,6 +203,8 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes("p", []) Meta.allow_tag_with_these_attributes("pre", []) Meta.allow_tag_with_these_attributes("strong", []) + Meta.allow_tag_with_these_attributes("sub", []) + Meta.allow_tag_with_these_attributes("sup", []) Meta.allow_tag_with_these_attributes("u", []) Meta.allow_tag_with_these_attributes("ul", []) From a9e75fa6a4ede24fbd4549d4deb06edf368e7c52 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 00:43:02 +0300 Subject: [PATCH 176/202] Add a task to benchmark timeline rendering --- lib/mix/tasks/pleroma/benchmark.ex | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/mix/tasks/pleroma/benchmark.ex b/lib/mix/tasks/pleroma/benchmark.ex index 5222cce80..a45940bf3 100644 --- a/lib/mix/tasks/pleroma/benchmark.ex +++ b/lib/mix/tasks/pleroma/benchmark.ex @@ -26,4 +26,28 @@ def run(["tag"]) do end }) end + + def run(["render_timeline", nickname]) do + start_pleroma() + user = Pleroma.User.get_by_nickname(nickname) + + activities = + %{} + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + |> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities() + |> Enum.reverse() + + Benchee.run(%{ + "render_timeline" => fn -> + Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{ + activities: activities, + for: user, + as: :activity + }) + end + }) + end end From bd5ad0af787e65bc05b7df64ef41c414900085af Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 00:47:30 +0300 Subject: [PATCH 177/202] Cache follow state --- lib/pleroma/user.ex | 22 +++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- lib/pleroma/web/activity_pub/utils.ex | 9 ++++++-- .../web/mastodon_api/views/account_view.ex | 6 ++--- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b67743846..a1040fe71 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -132,6 +132,28 @@ def user_info(%User{} = user, args \\ %{}) do |> Map.put(:follower_count, follower_count) end + def follow_state(%User{} = user, %User{} = target) do + follow_activity = Utils.fetch_latest_follow(user, target) + + if follow_activity, + do: follow_activity.data["state"], + # Ideally this would be nil, but then Cachex does not commit the value + else: false + end + + def get_cached_follow_state(user, target) do + key = "follow_state:#{user.ap_id}|#{target.ap_id}" + Cachex.fetch!(:user_cache, key, fn _ -> {:commit, follow_state(user, target)} end) + end + + def set_follow_state_cache(user_ap_id, target_ap_id, state) do + Cachex.put( + :user_cache, + "follow_state:#{user_ap_id}|#{target_ap_id}", + state + ) + end + def set_info_cache(user, args) do Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args)) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index cf55c9520..01052846f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -388,7 +388,8 @@ def unannounce( def follow(follower, followed, activity_id \\ nil, local \\ true) do with data <- make_follow_data(follower, followed, activity_id), {:ok, activity} <- insert(data, local), - :ok <- maybe_federate(activity) do + :ok <- maybe_federate(activity), + _ <- User.set_follow_state_cache(follower.ap_id, followed.ap_id, activity.data["state"]) do {:ok, activity} end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index fc5305c58..1c3058658 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -374,6 +374,7 @@ def update_follow_state_for_all( [state, actor, object] ) + User.set_follow_state_cache(actor, object, state) activity = Activity.get_by_id(activity.id) {:ok, activity} rescue @@ -382,12 +383,16 @@ def update_follow_state_for_all( end end - def update_follow_state(%Activity{} = activity, state) do + def update_follow_state( + %Activity{data: %{"actor" => actor, "object" => object}} = activity, + state + ) do with new_data <- activity.data |> Map.put("state", state), changeset <- Changeset.change(activity, data: new_data), - {:ok, activity} <- Repo.update(changeset) do + {:ok, activity} <- Repo.update(changeset), + _ <- User.set_follow_state_cache(actor, object, state) do {:ok, activity} end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 72c092f25..0ef568f0f 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -37,11 +37,11 @@ def render("relationship.json", %{user: nil, target: _target}) do end def render("relationship.json", %{user: %User{} = user, target: %User{} = target}) do - follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target) + follow_state = User.get_cached_follow_state(user, target) requested = - if follow_activity && !User.following?(target, user) do - follow_activity.data["state"] == "pending" + if follow_state && !User.following?(user, target) do + follow_state == "pending" else false end From e8a8d50138f70240bf853ba67008dc19e75127e8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 01:01:13 +0300 Subject: [PATCH 178/202] Collect stats immediately after init --- lib/pleroma/stats.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index a3b8a4d66..df80fbaa4 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -32,7 +32,7 @@ def get_peers do end def init(args) do - Process.send_after(self(), :run_update, @interval) + Process.send(self(), :run_update, []) {:ok, args} end From 2b94ae3b3911d78ee603163f7c8aa256ed65643f Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 15 Aug 2019 01:35:29 +0300 Subject: [PATCH 179/202] Do not check if actor is active when deleting a user --- CHANGELOG.md | 1 + lib/mix/tasks/pleroma/user.ex | 2 +- lib/pleroma/user.ex | 34 +++++++++---------- lib/pleroma/web/activity_pub/activity_pub.ex | 20 +++++------ .../web/activity_pub/transmogrifier.ex | 2 +- .../web/admin_api/admin_api_controller.ex | 4 +-- .../web/ostatus/handlers/delete_handler.ex | 2 +- test/user_test.exs | 3 +- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dccc36965..a7b776beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Security - OStatus: eliminate the possibility of a protocol downgrade attack. - OStatus: prevent following locked accounts, bypassing the approval process. +– ActivityPub: Do not check if actor is active when deleting a user ### Changed - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index f33d01429..a3f8bc945 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -176,7 +176,7 @@ def run(["rm", nickname]) do start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - User.perform(:delete, user, nil) + User.perform(:delete, user) shell_info("User #{nickname} deleted.") else _ -> diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 14057a0e4..7d18f099e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1029,26 +1029,13 @@ def update_notification_settings(%User{} = user, settings \\ %{}) do |> update_and_set_cache() end - @spec perform(atom(), User.t()) :: {:ok, User.t()} - def perform(:fetch_initial_posts, %User{} = user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - Enum.each( - # Insert all the posts in reverse order, so they're in the right order on the timeline - Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), - &Pleroma.Web.Federator.incoming_ap_doc/1 - ) - - {:ok, user} - end - @spec delete(User.t()) :: :ok - def delete(%User{} = user, actor \\ nil), - do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user, actor]) + def delete(%User{} = user), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user]) @spec perform(atom(), User.t()) :: {:ok, User.t()} - def perform(:delete, %User{} = user, actor) do - {:ok, _user} = ActivityPub.delete(user, actor: actor) + def perform(:delete, %User{} = user) do + {:ok, _user} = ActivityPub.delete(user) # Remove all relationships {:ok, followers} = User.get_followers(user) @@ -1070,6 +1057,19 @@ def perform(:delete, %User{} = user, actor) do Repo.delete(user) end + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:fetch_initial_posts, %User{} = user) do + pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) + + Enum.each( + # Insert all the posts in reverse order, so they're in the right order on the timeline + Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), + &Pleroma.Web.Federator.incoming_ap_doc/1 + ) + + {:ok, user} + end + def perform(:deactivate_async, user, status), do: deactivate(user, status) @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8f669acb9..da873b7b0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -61,7 +61,9 @@ defp get_recipients(data) do {recipients, to, cc} end - defp check_actor_is_active(actor) do + defp check_actor_is_active(true, _), do: :ok + + defp check_actor_is_active(false, actor) do if not is_nil(actor) do with user <- User.get_cached_by_ap_id(actor), false <- user.info.deactivated do @@ -119,10 +121,10 @@ def increase_poll_votes_if_vote(%{ def increase_poll_votes_if_vote(_create_data), do: :noop - def insert(map, local \\ true, fake \\ false) when is_map(map) do + def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do with nil <- Activity.normalize(map), map <- lazy_put_activity_defaults(map, fake), - :ok <- check_actor_is_active(map["actor"]), + :ok <- check_actor_is_active(bypass_actor_check, map["actor"]), {_, true} <- {:remote_limit_error, check_remote_limit(map)}, {:ok, map} <- MRF.filter(map), {recipients, _, _} = get_recipients(map), @@ -403,22 +405,20 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do end end - def delete(data, opts \\ %{actor: nil, local: true}) - - def delete(%User{ap_id: ap_id, follower_address: follower_address} = user, opts) do + def delete(%User{ap_id: ap_id, follower_address: follower_address} = user) do with data <- %{ "to" => [follower_address], "type" => "Delete", - "actor" => opts[:actor] || ap_id, + "actor" => ap_id, "object" => %{"type" => "Person", "id" => ap_id} }, - {:ok, activity} <- insert(data, true, true), + {:ok, activity} <- insert(data, true, true, true), :ok <- maybe_federate(activity) do {:ok, user} end end - def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, opts) do + def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do user = User.get_cached_by_ap_id(actor) to = (object.data["to"] || []) ++ (object.data["cc"] || []) @@ -430,7 +430,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, opts) do "to" => to, "deleted_activity_id" => activity && activity.id }, - {:ok, activity} <- insert(data, opts[:local], false), + {:ok, activity} <- insert(data, local, false), stream_out_participations(object, user), _ <- decrease_replies_count_if_reply(object), # Changing note count prior to enqueuing federation task in order to avoid diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b34ef73c0..5403b71d8 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -649,7 +649,7 @@ def handle_incoming( {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id), :ok <- Containment.contain_origin(actor.ap_id, object.data), - {:ok, activity} <- ActivityPub.delete(object, local: false) do + {:ok, activity} <- ActivityPub.delete(object, false) do {:ok, activity} else nil -> diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 63c9a7d7f..2d3d0adc4 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -25,9 +25,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do action_fallback(:errors) - def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do + def user_delete(conn, %{"nickname" => nickname}) do User.get_cached_by_nickname(nickname) - |> User.delete(admin.ap_id) + |> User.delete() conn |> json(nickname) diff --git a/lib/pleroma/web/ostatus/handlers/delete_handler.ex b/lib/pleroma/web/ostatus/handlers/delete_handler.ex index ac2dc115c..b2f9f3946 100644 --- a/lib/pleroma/web/ostatus/handlers/delete_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/delete_handler.ex @@ -11,7 +11,7 @@ defmodule Pleroma.Web.OStatus.DeleteHandler do def handle_delete(entry, _doc \\ nil) do with id <- XML.string_from_xpath("//id", entry), %Object{} = object <- Object.normalize(id), - {:ok, delete} <- ActivityPub.delete(object, local: false) do + {:ok, delete} <- ActivityPub.delete(object, false) do delete end end diff --git a/test/user_test.exs b/test/user_test.exs index e2da8d84b..755c6005d 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -999,10 +999,9 @@ test ".delete_user_activities deletes all create activities", %{user: user} do end test "it deletes deactivated user" do - admin = insert(:user, %{info: %{is_admin: true}}) {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache() - assert {:ok, _} = User.delete(user, admin.ap_id) + assert {:ok, _} = User.delete(user) refute User.get_by_id(user.id) end From b27fafe161241c954b713281bebd6ffe1e990884 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Thu, 15 Aug 2019 01:42:43 +0300 Subject: [PATCH 180/202] Fix CHANGELOG entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7b776beb..161f88176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Security - OStatus: eliminate the possibility of a protocol downgrade attack. - OStatus: prevent following locked accounts, bypassing the approval process. -– ActivityPub: Do not check if actor is active when deleting a user ### Changed - **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config @@ -39,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Invalid SemVer version generation, when the current branch does not have commits ahead of tag/checked out on a tag - Pleroma.Upload base_url was not automatically whitelisted by MediaProxy. Now your custom CDN or file hosting will be accessed directly as expected. - Report email not being sent to admins when the reporter is a remote user +- ActivityPub: Deactivated user deletion ### Added - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) From a4a3e3becd5e008dbfa9a23157ae4b16a0652bce Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 17:37:30 +0300 Subject: [PATCH 181/202] Hide muted theads from home/public timelines unless `with_muted` is set --- lib/pleroma/activity.ex | 1 + lib/pleroma/web/activity_pub/activity_pub.ex | 20 +++++++++++------ lib/pleroma/web/streamer.ex | 6 ++--- test/web/activity_pub/activity_pub_test.exs | 23 ++++++++++++++++++++ test/web/streamer_test.exs | 20 +++++++++++++++++ 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index baf1e7722..35612c882 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -96,6 +96,7 @@ def with_set_thread_muted_field(query, %User{} = user) do from([a] in query, left_join: tm in ThreadMute, on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data), + as: :thread_mute, select: %Activity{a | thread_muted?: not is_nil(tm.id)} ) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index cf55c9520..defccade8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -790,14 +790,20 @@ defp restrict_reblogs(query, _), do: query defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query - defp restrict_muted(query, %{"muting_user" => %User{info: info}}) do + defp restrict_muted(query, %{"muting_user" => %User{info: info}} = opts) do mutes = info.mutes - from( - activity in query, - where: fragment("not (? = ANY(?))", activity.actor, ^mutes), - where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes) - ) + query = + from([activity] in query, + where: fragment("not (? = ANY(?))", activity.actor, ^mutes), + where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes) + ) + + unless opts["skip_preload"] do + from([thread_mute: tm] in query, where: is_nil(tm)) + else + query + end end defp restrict_muted(query, _), do: query @@ -898,7 +904,7 @@ defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query defp maybe_set_thread_muted_field(query, opts) do query - |> Activity.with_set_thread_muted_field(opts["user"]) + |> Activity.with_set_thread_muted_field(opts["muting_user"] || opts["user"]) end defp maybe_order(query, %{order: :desc}) do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index bbaddd852..826be2f9a 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -113,8 +113,7 @@ def handle_cast( |> Map.get("#{topic}:#{item.user_id}", []) |> Enum.each(fn socket -> with %User{} = user <- User.get_cached_by_ap_id(socket.assigns[:user].ap_id), - true <- should_send?(user, item), - false <- CommonAPI.thread_muted?(user, item.activity) do + true <- should_send?(user, item) do send( socket.transport_pid, {:text, represent_notification(socket.assigns[:user], item)} @@ -236,7 +235,8 @@ defp should_send?(%User{} = user, %Activity{} = item) do %{host: parent_host} <- URI.parse(parent.data["actor"]), false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host), false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host), - true <- thread_containment(item, user) do + true <- thread_containment(item, user), + false <- CommonAPI.thread_muted?(user, item) do true else _ -> false diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index d723f331f..0377d29f6 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -538,6 +538,29 @@ test "doesn't return muted activities" do assert Enum.member?(activities, activity_one) end + test "doesn't return thread muted activities" do + user = insert(:user) + activity_one = insert(:note_activity) + note_two = insert(:note, data: %{"context" => "suya.."}) + activity_two = insert(:note_activity, note: note_two) + + {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) + + assert [activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user}) + end + + test "returns thread muted activities when with_muted is set" do + user = insert(:user) + activity_one = insert(:note_activity) + note_two = insert(:note, data: %{"context" => "suya.."}) + activity_two = insert(:note_activity, note: note_two) + + {:ok, activity_two} = CommonAPI.add_mute(user, activity_two) + + assert [activity_two, activity_one] = + ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true}) + end + test "does include announces on request" do activity_three = insert(:note_activity) user = insert(:user) diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index d47b37efb..5b7fe44d4 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -414,6 +414,26 @@ test "it doesn't send muted reblogs" do Task.await(task) end + test "it doesn't send posts from muted threads" do + user = insert(:user) + user2 = insert(:user) + {:ok, user2, user, _activity} = CommonAPI.follow(user2, user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"}) + + {:ok, activity} = CommonAPI.add_mute(user2, activity) + + task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) + + Streamer.add_socket( + "user", + %{transport_pid: task.pid, assigns: %{user: user2}} + ) + + Streamer.stream("user", activity) + Task.await(task) + end + describe "direct streams" do setup do GenServer.start(Streamer, %{}, name: Streamer) From 1ad71592adb47762287aec8c36d0fca565c38362 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 17:41:26 +0300 Subject: [PATCH 182/202] Parallelize template rendering --- lib/mix/tasks/pleroma/benchmark.ex | 38 ++++++++++++++----- .../web/mastodon_api/views/status_view.ex | 4 +- lib/pleroma/web/web.ex | 18 ++++++++- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/mix/tasks/pleroma/benchmark.ex b/lib/mix/tasks/pleroma/benchmark.ex index a45940bf3..4cc634727 100644 --- a/lib/mix/tasks/pleroma/benchmark.ex +++ b/lib/mix/tasks/pleroma/benchmark.ex @@ -37,17 +37,37 @@ def run(["render_timeline", nickname]) do |> Map.put("blocking_user", user) |> Map.put("muting_user", user) |> Map.put("user", user) + |> Map.put("limit", 80) |> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities() |> Enum.reverse() - Benchee.run(%{ - "render_timeline" => fn -> - Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{ - activities: activities, - for: user, - as: :activity - }) - end - }) + inputs = %{ + "One activity" => Enum.take_random(activities, 1), + "Ten activities" => Enum.take_random(activities, 10), + "Twenty activities" => Enum.take_random(activities, 20), + "Forty activities" => Enum.take_random(activities, 40), + "Eighty activities" => Enum.take_random(activities, 80) + } + + Benchee.run( + %{ + "Parallel rendering" => fn activities -> + Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{ + activities: activities, + for: user, + as: :activity + }) + end, + "Standart rendering" => fn activities -> + Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{ + activities: activities, + for: user, + as: :activity, + parallel: false + }) + end + }, + inputs: inputs + ) end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 492af1702..7e4e99280 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -70,12 +70,14 @@ defp reblogged?(activity, user) do def render("index.json", opts) do replied_to_activities = get_replied_to_activities(opts.activities) + parallel = unless is_nil(opts[:parallel]), do: opts[:parallel], else: true opts.activities |> safe_render_many( StatusView, "status.json", - Map.put(opts, :replied_to_activities, replied_to_activities) + Map.put(opts, :replied_to_activities, replied_to_activities), + parallel ) end diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex index 687346554..bfb6c7287 100644 --- a/lib/pleroma/web/web.ex +++ b/lib/pleroma/web/web.ex @@ -66,9 +66,23 @@ def safe_render(view, template, assigns \\ %{}) do end @doc """ - Same as `render_many/4` but wrapped in rescue block. + Same as `render_many/4` but wrapped in rescue block and parallelized (unless disabled by passing false as a fifth argument). """ - def safe_render_many(collection, view, template, assigns \\ %{}) do + def safe_render_many(collection, view, template, assigns \\ %{}, parallel \\ true) + + def safe_render_many(collection, view, template, assigns, true) do + Enum.map(collection, fn resource -> + Task.async(fn -> + as = Map.get(assigns, :as) || view.__resource__ + assigns = Map.put(assigns, as, resource) + safe_render(view, template, assigns) + end) + end) + |> Enum.map(&Task.await(&1, :infinity)) + |> Enum.filter(& &1) + end + + def safe_render_many(collection, view, template, assigns, false) do Enum.map(collection, fn resource -> as = Map.get(assigns, :as) || view.__resource__ assigns = Map.put(assigns, as, resource) From fba3c16d205408bf6ba00e40bad7d8b5a7abe510 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 15 Aug 2019 20:36:20 +0300 Subject: [PATCH 183/202] Fix OAuth cleanup worker unconditionally starting !1576 removed enabled/disabled check from the worker, in favor of just not starting it in application.ex if disabled. However a line unconditionally starting the worker was removed --- lib/pleroma/application.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index aa673188f..25e56b9e2 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -41,7 +41,6 @@ def start(_type, _args) do hackney_pool_children() ++ [ Pleroma.Web.Federator.RetryQueue, - Pleroma.Web.OAuth.Token.CleanWorker, Pleroma.Stats, %{ id: :web_push_init, From 6a3b1a526eb1a3ea49aca7914ed7ba8736c52059 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 15 Aug 2019 15:34:41 -0500 Subject: [PATCH 184/202] max_body_size -> max_body_length, as it should be --- lib/pleroma/reverse_proxy/reverse_proxy.ex | 4 ++-- test/reverse_proxy_test.exs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/reverse_proxy/reverse_proxy.ex b/lib/pleroma/reverse_proxy/reverse_proxy.ex index 1f98f215c..7518e4c3c 100644 --- a/lib/pleroma/reverse_proxy/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy/reverse_proxy.ex @@ -109,7 +109,7 @@ def call(conn = %{method: method}, url, opts) when method in @methods do end with {:ok, code, headers, client} <- request(method, url, req_headers, hackney_opts), - :ok <- header_length_constraint(headers, Keyword.get(opts, :max_body_length)) do + :ok <- header_length_constraint(headers, Keyword.get(opts, :max_body_length, @max_body_length)) do response(conn, client, url, code, headers, opts) else {:ok, code, headers} -> @@ -200,7 +200,7 @@ defp chunk_reply(conn, client, opts, sent_so_far, duration) do {:ok, data} <- client().stream_body(client), {:ok, duration} <- increase_read_duration(duration), sent_so_far = sent_so_far + byte_size(data), - :ok <- body_size_constraint(sent_so_far, Keyword.get(opts, :max_body_size)), + :ok <- body_size_constraint(sent_so_far, Keyword.get(opts, :max_body_length, @max_body_length)), {:ok, conn} <- chunk(conn, data) do chunk_reply(conn, client, opts, sent_so_far, duration) else diff --git a/test/reverse_proxy_test.exs b/test/reverse_proxy_test.exs index f4b7d6add..3a83c4c48 100644 --- a/test/reverse_proxy_test.exs +++ b/test/reverse_proxy_test.exs @@ -108,11 +108,11 @@ defp stream_mock(invokes, with_close? \\ false) do end end - test "max_body_size returns error if streaming body more than that option", %{conn: conn} do + test "max_body_length returns error if streaming body more than that option", %{conn: conn} do stream_mock(3, true) assert capture_log(fn -> - ReverseProxy.call(conn, "/stream-bytes/50", max_body_size: 30) + ReverseProxy.call(conn, "/stream-bytes/50", max_body_length: 30) end) =~ "[warn] Elixir.Pleroma.ReverseProxy request to /stream-bytes/50 failed while reading/chunking: :body_too_large" end From 158231cd20ceabf805ce49ae2b4d465e09e34d69 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 16 Aug 2019 18:32:25 +0700 Subject: [PATCH 185/202] Add configurable colors and logo for the digest template --- config/config.exs | 11 ++ docs/config.md | 5 + lib/pleroma/emails/user_email.ex | 88 +++++----- .../web/templates/email/digest.html.eex | 163 +++++++++--------- 4 files changed, 143 insertions(+), 124 deletions(-) diff --git a/config/config.exs b/config/config.exs index d2325edbc..4941953e5 100644 --- a/config/config.exs +++ b/config/config.exs @@ -507,6 +507,17 @@ config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Sendmail, enabled: false +config :pleroma, Pleroma.Emails.UserEmail, + logo: nil, + styling: %{ + link_color: "#d8a070", + background_color: "#2C3645", + content_background_color: "#1B2635", + header_color: "#d8a070", + text_color: "#b9b9ba", + text_muted_color: "#b9b9ba" + } + config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics" config :pleroma, Pleroma.ScheduledActivity, diff --git a/docs/config.md b/docs/config.md index 703ef67dd..8360e640e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -548,6 +548,11 @@ Email notifications settings. - interval: Minimum interval between digest emails to one user - inactivity_threshold: Minimum user inactivity threshold +## Pleroma.Emails.UserEmail + +- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo. +- `:styling` - a map with color settings for email templates. + ## OAuth consumer mode OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.). diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 3b5e64019..40b67ff56 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -7,21 +7,21 @@ defmodule Pleroma.Emails.UserEmail do use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email} + alias Pleroma.Config + alias Pleroma.User alias Pleroma.Web.Endpoint alias Pleroma.Web.Router - defp instance_config, do: Pleroma.Config.get(:instance) - - defp instance_name, do: instance_config()[:name] + defp instance_name, do: Config.get([:instance, :name]) defp sender do - email = Keyword.get(instance_config(), :notify_email, instance_config()[:email]) + email = Config.get([:instance, :notify_email]) || Config.get([:instance, :email]) {instance_name(), email} end defp recipient(email, nil), do: email defp recipient(email, name), do: {name, email} - defp recipient(%Pleroma.User{} = user), do: recipient(user.email, user.name) + defp recipient(%User{} = user), do: recipient(user.email, user.name) def password_reset_email(user, token) when is_binary(token) do password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token) @@ -93,50 +93,54 @@ def account_confirmation_email(user) do Includes Mentions and New Followers data If there are no mentions (even when new followers exist), the function will return nil """ - @spec digest_email(Pleroma.User.t()) :: Swoosh.Email.t() | nil + @spec digest_email(User.t()) :: Swoosh.Email.t() | nil def digest_email(user) do - new_notifications = - Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at) - |> Enum.reduce(%{followers: [], mentions: []}, fn - %{activity: %{data: %{"type" => "Create"}, actor: actor} = activity} = notification, - acc -> - new_mention = %{ - data: notification, - object: Pleroma.Object.normalize(activity), - from: Pleroma.User.get_by_ap_id(actor) - } + notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at) - %{acc | mentions: [new_mention | acc.mentions]} + mentions = + notifications + |> Enum.filter(&(&1.activity.data["type"] == "Create")) + |> Enum.map(fn notification -> + object = Pleroma.Object.normalize(notification.activity) + object = update_in(object.data["content"], &format_links/1) - %{activity: %{data: %{"type" => "Follow"}, actor: actor} = activity} = notification, - acc -> - new_follower = %{ - data: notification, - object: Pleroma.Object.normalize(activity), - from: Pleroma.User.get_by_ap_id(actor) - } - - %{acc | followers: [new_follower | acc.followers]} - - _, acc -> - acc + %{ + data: notification, + object: object, + from: User.get_by_ap_id(notification.activity.actor) + } end) - with [_ | _] = mentions <- new_notifications.mentions do - mentions = - Enum.map(mentions, fn mention -> - update_in(mention.object.data["content"], &format_links/1) - end) + followers = + notifications + |> Enum.filter(&(&1.activity.data["type"] == "Follow")) + |> Enum.map(fn notification -> + %{ + data: notification, + object: Pleroma.Object.normalize(notification.activity), + from: User.get_by_ap_id(notification.activity.actor) + } + end) + + unless Enum.empty?(mentions) do + styling = Config.get([__MODULE__, :styling]) + logo = Config.get([__MODULE__, :logo]) html_data = %{ instance: instance_name(), user: user, mentions: mentions, - followers: new_notifications.followers, - unsubscribe_link: unsubscribe_url(user, "digest") + followers: followers, + unsubscribe_link: unsubscribe_url(user, "digest"), + styling: styling } - logo_path = Path.join(:code.priv_dir(:pleroma), "static/static/logo.png") + logo_path = + if is_nil(logo) do + Path.join(:code.priv_dir(:pleroma), "static/static/logo.png") + else + Path.join(Config.get([:instance, :static_dir]), logo) + end new() |> to(recipient(user)) @@ -145,17 +149,15 @@ def digest_email(user) do |> put_layout(false) |> render_body("digest.html", html_data) |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline)) - else - _ -> - nil end end defp format_links(str) do re = ~r//iU + %{link_color: color} = Config.get([__MODULE__, :styling]) Regex.replace(re, str, fn link -> - String.replace(link, " user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false} |> Pleroma.JWT.generate_and_sign!() |> Base.encode64() - Router.Helpers.subscription_url(Pleroma.Web.Endpoint, :unsubscribe, token) + Router.Helpers.subscription_url(Endpoint, :unsubscribe, token) end end diff --git a/lib/pleroma/web/templates/email/digest.html.eex b/lib/pleroma/web/templates/email/digest.html.eex index 61d57093b..860df5f9c 100644 --- a/lib/pleroma/web/templates/email/digest.html.eex +++ b/lib/pleroma/web/templates/email/digest.html.eex @@ -21,7 +21,8 @@ } a { - color: #d8a070; + + color: <%= @styling.link_color %>; text-decoration: none; } @@ -100,21 +101,21 @@ - + -