diff options
Diffstat (limited to 'lib/mix')
| -rw-r--r-- | lib/mix/pleroma.ex | 20 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/app.ex | 49 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/benchmark.ex | 41 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/config.ex | 158 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/database.ex | 8 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/digest.ex | 7 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/docs.ex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/ecto/ecto.ex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/ecto/migrate.ex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/ecto/rollback.ex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/email.ex | 24 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/emoji.ex | 95 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/instance.ex | 17 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/notification_settings.ex | 83 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/refresh_counter_cache.ex | 46 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/relay.ex | 4 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/robotstxt.ex | 3 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/uploads.ex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/user.ex | 61 | 
19 files changed, 507 insertions, 119 deletions
| diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex index faeb30e1d..3ad6edbfb 100644 --- a/lib/mix/pleroma.ex +++ b/lib/mix/pleroma.ex @@ -1,12 +1,30 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Pleroma do    @doc "Common functions to be reused in mix tasks"    def start_pleroma do      Application.put_env(:phoenix, :serve_endpoints, false, persistent: true) + +    if Pleroma.Config.get(:env) != :test do +      Application.put_env(:logger, :console, level: :debug) +    end +      {:ok, _} = Application.ensure_all_started(:pleroma) + +    if Pleroma.Config.get(:env) not in [:test, :benchmark] do +      pleroma_rebooted?() +    end +  end + +  defp pleroma_rebooted? do +    if Restarter.Pleroma.rebooted?() do +      :ok +    else +      Process.sleep(10) +      pleroma_rebooted?() +    end    end    def load_pleroma do diff --git a/lib/mix/tasks/pleroma/app.ex b/lib/mix/tasks/pleroma/app.ex new file mode 100644 index 000000000..463e2449f --- /dev/null +++ b/lib/mix/tasks/pleroma/app.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.App do +  @moduledoc File.read!("docs/administration/CLI_tasks/oauth_app.md") +  use Mix.Task + +  import Mix.Pleroma + +  @shortdoc "Creates trusted OAuth App" + +  def run(["create" | options]) do +    start_pleroma() + +    {opts, _} = +      OptionParser.parse!(options, +        strict: [name: :string, redirect_uri: :string, scopes: :string], +        aliases: [n: :name, r: :redirect_uri, s: :scopes] +      ) + +    scopes = +      if opts[:scopes] do +        String.split(opts[:scopes], ",") +      else +        ["read", "write", "follow", "push"] +      end + +    params = %{ +      client_name: opts[:name], +      redirect_uris: opts[:redirect_uri], +      trusted: true, +      scopes: scopes +    } + +    with {:ok, app} <- Pleroma.Web.OAuth.App.create(params) do +      shell_info("#{app.client_name} successfully created:") +      shell_info("App client_id: " <> app.client_id) +      shell_info("App client_secret: " <> app.client_secret) +    else +      {:error, changeset} -> +        shell_error("Creating failed:") + +        Enum.each(Pleroma.Web.OAuth.App.errors(changeset), fn {key, error} -> +          shell_error("#{key}: #{error}") +        end) +    end +  end +end diff --git a/lib/mix/tasks/pleroma/benchmark.ex b/lib/mix/tasks/pleroma/benchmark.ex index 84dccf7f3..dd2b9c8f2 100644 --- a/lib/mix/tasks/pleroma/benchmark.ex +++ b/lib/mix/tasks/pleroma/benchmark.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Benchmark do @@ -74,4 +74,43 @@ defmodule Mix.Tasks.Pleroma.Benchmark do        inputs: inputs      )    end + +  def run(["adapters"]) do +    start_pleroma() + +    :ok = +      Pleroma.Gun.Conn.open( +        "https://httpbin.org/stream-bytes/1500", +        :gun_connections +      ) + +    Process.sleep(1_500) + +    Benchee.run( +      %{ +        "Without conn and without pool" => fn -> +          {:ok, %Tesla.Env{}} = +            Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [], +              adapter: [pool: :no_pool, receive_conn: false] +            ) +        end, +        "Without conn and with pool" => fn -> +          {:ok, %Tesla.Env{}} = +            Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [], +              adapter: [receive_conn: false] +            ) +        end, +        "With reused conn and without pool" => fn -> +          {:ok, %Tesla.Env{}} = +            Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [], +              adapter: [pool: :no_pool] +            ) +        end, +        "With reused conn and with pool" => fn -> +          {:ok, %Tesla.Env{}} = Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500") +        end +      }, +      parallel: 10 +    ) +  end  end diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 11e4fde43..5c9ef6904 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -1,72 +1,150 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Config do    use Mix.Task +    import Mix.Pleroma + +  alias Pleroma.ConfigDB    alias Pleroma.Repo -  alias Pleroma.Web.AdminAPI.Config +    @shortdoc "Manages the location of the config"    @moduledoc File.read!("docs/administration/CLI_tasks/config.md") +    def run(["migrate_to_db"]) do      start_pleroma() +    migrate_to_db() +  end + +  def run(["migrate_from_db" | options]) do +    start_pleroma() -    if Pleroma.Config.get([:instance, :dynamic_configuration]) do -      Application.get_all_env(:pleroma) -      |> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end) -      |> Enum.each(fn {k, v} -> -        key = to_string(k) |> String.replace("Elixir.", "") +    {opts, _} = +      OptionParser.parse!(options, +        strict: [env: :string, delete: :boolean], +        aliases: [d: :delete] +      ) + +    migrate_from_db(opts) +  end -        key = -          if String.starts_with?(key, "Pleroma.") do -            key +  @spec migrate_to_db(Path.t() | nil) :: any() +  def migrate_to_db(file_path \\ nil) do +    if Pleroma.Config.get([:configurable_from_database]) do +      config_file = +        if file_path do +          file_path +        else +          if Pleroma.Config.get(:release) do +            Pleroma.Config.get(:config_path)            else -            ":" <> key +            "config/#{Pleroma.Config.get(:env)}.secret.exs"            end +        end -        {:ok, _} = Config.update_or_create(%{group: "pleroma", key: key, value: v}) -        Mix.shell().info("#{key} is migrated.") -      end) - -      Mix.shell().info("Settings migrated.") +      do_migrate_to_db(config_file)      else -      Mix.shell().info( -        "Migration is not allowed by config. You can change this behavior in instance settings." -      ) +      migration_error()      end    end -  def run(["migrate_from_db", env, delete?]) do -    start_pleroma() +  defp do_migrate_to_db(config_file) do +    if File.exists?(config_file) do +      Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;") +      Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;") -    delete? = if delete? == "true", do: true, else: false +      custom_config = +        config_file +        |> read_file() +        |> elem(0) -    if Pleroma.Config.get([:instance, :dynamic_configuration]) do -      config_path = "config/#{env}.exported_from_db.secret.exs" +      custom_config +      |> Keyword.keys() +      |> Enum.each(&create(&1, custom_config)) +    else +      shell_info("To migrate settings, you must define custom settings in #{config_file}.") +    end +  end -      {:ok, file} = File.open(config_path, [:write]) -      IO.write(file, "use Mix.Config\r\n") +  defp create(group, settings) do +    group +    |> Pleroma.Config.Loader.filter_group(settings) +    |> Enum.each(fn {key, value} -> +      key = inspect(key) +      {:ok, _} = ConfigDB.update_or_create(%{group: inspect(group), key: key, value: value}) -      Repo.all(Config) -      |> Enum.each(fn config -> -        IO.write( -          file, -          "config :#{config.group}, #{config.key}, #{inspect(Config.from_binary(config.value))}\r\n\r\n" -        ) +      shell_info("Settings for key #{key} migrated.") +    end) + +    shell_info("Settings for group :#{group} migrated.") +  end -        if delete? do -          {:ok, _} = Repo.delete(config) -          Mix.shell().info("#{config.key} deleted from DB.") +  defp migrate_from_db(opts) do +    if Pleroma.Config.get([:configurable_from_database]) do +      env = opts[:env] || "prod" + +      config_path = +        if Pleroma.Config.get(:release) do +          :config_path +          |> Pleroma.Config.get() +          |> Path.dirname() +        else +          "config"          end -      end) +        |> Path.join("#{env}.exported_from_db.secret.exs") + +      file = File.open!(config_path, [:write, :utf8]) + +      IO.write(file, config_header()) -      File.close(file) +      ConfigDB +      |> Repo.all() +      |> Enum.each(&write_and_delete(&1, file, opts[:delete])) + +      :ok = File.close(file)        System.cmd("mix", ["format", config_path])      else -      Mix.shell().info( -        "Migration is not allowed by config. You can change this behavior in instance settings." -      ) +      migration_error()      end    end + +  defp migration_error do +    shell_error( +      "Migration is not allowed in config. You can change this behavior by setting `configurable_from_database` to true." +    ) +  end + +  if Code.ensure_loaded?(Config.Reader) do +    defp config_header, do: "import Config\r\n\r\n" +    defp read_file(config_file), do: Config.Reader.read_imports!(config_file) +  else +    defp config_header, do: "use Mix.Config\r\n\r\n" +    defp read_file(config_file), do: Mix.Config.eval!(config_file) +  end + +  defp write_and_delete(config, file, delete?) do +    config +    |> write(file) +    |> delete(delete?) +  end + +  defp write(config, file) do +    value = +      config.value +      |> ConfigDB.from_binary() +      |> inspect(limit: :infinity) + +    IO.write(file, "config #{config.group}, #{config.key}, #{value}\r\n\r\n") + +    config +  end + +  defp delete(config, true) do +    {:ok, _} = Repo.delete(config) +    shell_info("#{config.key} deleted from DB.") +  end + +  defp delete(_config, _), do: :ok  end diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 8a827ca80..778de162f 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Database do @@ -52,9 +52,9 @@ defmodule Mix.Tasks.Pleroma.Database do    def run(["update_users_following_followers_counts"]) do      start_pleroma() -    users = Repo.all(User) -    Enum.each(users, &User.remove_duplicated_following/1) -    Enum.each(users, &User.update_follower_count/1) +    User +    |> Repo.all() +    |> Enum.each(&User.update_follower_count/1)    end    def run(["prune_objects" | args]) do diff --git a/lib/mix/tasks/pleroma/digest.ex b/lib/mix/tasks/pleroma/digest.ex index 7d09e70c5..3595f912d 100644 --- a/lib/mix/tasks/pleroma/digest.ex +++ b/lib/mix/tasks/pleroma/digest.ex @@ -1,5 +1,6 @@  defmodule Mix.Tasks.Pleroma.Digest do    use Mix.Task +  import Mix.Pleroma    @shortdoc "Manages digest emails"    @moduledoc File.read!("docs/administration/CLI_tasks/digest.md") @@ -22,12 +23,10 @@ defmodule Mix.Tasks.Pleroma.Digest do      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})") +      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}" -        ) +        shell_info("Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}")      end    end  end diff --git a/lib/mix/tasks/pleroma/docs.ex b/lib/mix/tasks/pleroma/docs.ex index 0d2663648..6088fc71d 100644 --- a/lib/mix/tasks/pleroma/docs.ex +++ b/lib/mix/tasks/pleroma/docs.ex @@ -28,7 +28,7 @@ defmodule Mix.Tasks.Pleroma.Docs do    defp do_run(implementation) do      start_pleroma() -    with {descriptions, _paths} <- Mix.Config.eval!("config/description.exs"), +    with descriptions <- Pleroma.Config.Loader.read("config/description.exs"),           {:ok, file_path} <-             Pleroma.Docs.Generator.process(               implementation, diff --git a/lib/mix/tasks/pleroma/ecto/ecto.ex b/lib/mix/tasks/pleroma/ecto/ecto.ex index 36808b93f..3363cd45f 100644 --- a/lib/mix/tasks/pleroma/ecto/ecto.ex +++ b/lib/mix/tasks/pleroma/ecto/ecto.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-onl  defmodule Mix.Tasks.Pleroma.Ecto do diff --git a/lib/mix/tasks/pleroma/ecto/migrate.ex b/lib/mix/tasks/pleroma/ecto/migrate.ex index d87b6957d..bc8ed29fb 100644 --- a/lib/mix/tasks/pleroma/ecto/migrate.ex +++ b/lib/mix/tasks/pleroma/ecto/migrate.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-onl  defmodule Mix.Tasks.Pleroma.Ecto.Migrate do diff --git a/lib/mix/tasks/pleroma/ecto/rollback.ex b/lib/mix/tasks/pleroma/ecto/rollback.ex index a1af73fa1..f43bd0b98 100644 --- a/lib/mix/tasks/pleroma/ecto/rollback.ex +++ b/lib/mix/tasks/pleroma/ecto/rollback.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-onl  defmodule Mix.Tasks.Pleroma.Ecto.Rollback do diff --git a/lib/mix/tasks/pleroma/email.ex b/lib/mix/tasks/pleroma/email.ex new file mode 100644 index 000000000..d3fac6ec8 --- /dev/null +++ b/lib/mix/tasks/pleroma/email.ex @@ -0,0 +1,24 @@ +defmodule Mix.Tasks.Pleroma.Email do +  use Mix.Task +  import Mix.Pleroma + +  @shortdoc "Simple Email test" +  @moduledoc File.read!("docs/administration/CLI_tasks/email.md") + +  def run(["test" | args]) do +    Mix.Pleroma.start_pleroma() + +    {options, [], []} = +      OptionParser.parse( +        args, +        strict: [ +          to: :string +        ] +      ) + +    email = Pleroma.Emails.AdminEmail.test_email(options[:to]) +    {:ok, _} = Pleroma.Emails.Mailer.deliver(email) + +    shell_info("Test email has been sent to #{inspect(email.to)} from #{inspect(email.from)}") +  end +end diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index 35669af27..cdffa88b2 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -1,20 +1,21 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Emoji do    use Mix.Task +  import Mix.Pleroma    @shortdoc "Manages emoji packs"    @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")    def run(["ls-packs" | args]) do -    Application.ensure_all_started(:hackney) +    start_pleroma()      {options, [], []} = parse_global_opts(args) -    manifest = -      fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest()) +    url_or_path = options[:manifest] || default_manifest() +    manifest = fetch_manifest(url_or_path)      Enum.each(manifest, fn {name, info} ->        to_print = [ @@ -35,13 +36,13 @@ defmodule Mix.Tasks.Pleroma.Emoji do    end    def run(["get-packs" | args]) do -    Application.ensure_all_started(:hackney) +    start_pleroma()      {options, pack_names, []} = parse_global_opts(args) -    manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest() +    url_or_path = options[:manifest] || default_manifest() -    manifest = fetch_manifest(manifest_url) +    manifest = fetch_manifest(url_or_path)      for pack_name <- pack_names do        if Map.has_key?(manifest, pack_name) do @@ -74,7 +75,10 @@ defmodule Mix.Tasks.Pleroma.Emoji do          end          # The url specified in files should be in the same directory -        files_url = Path.join(Path.dirname(manifest_url), pack["files"]) +        files_url = +          url_or_path +          |> Path.dirname() +          |> Path.join(pack["files"])          IO.puts(            IO.ANSI.format([ @@ -132,38 +136,51 @@ defmodule Mix.Tasks.Pleroma.Emoji do      end    end -  def run(["gen-pack", src]) do -    Application.ensure_all_started(:hackney) +  def run(["gen-pack" | args]) do +    start_pleroma() + +    {opts, [src], []} = +      OptionParser.parse( +        args, +        strict: [ +          name: :string, +          license: :string, +          homepage: :string, +          description: :string, +          files: :string, +          extensions: :string +        ] +      )      proposed_name = Path.basename(src) |> Path.rootname() -    name = String.trim(IO.gets("Pack name [#{proposed_name}]: ")) -    # If there's no name, use the default one -    name = if String.length(name) > 0, do: name, else: proposed_name - -    license = String.trim(IO.gets("License: ")) -    homepage = String.trim(IO.gets("Homepage: ")) -    description = String.trim(IO.gets("Description: ")) +    name = get_option(opts, :name, "Pack name:", proposed_name) +    license = get_option(opts, :license, "License:") +    homepage = get_option(opts, :homepage, "Homepage:") +    description = get_option(opts, :description, "Description:") -    proposed_files_name = "#{name}.json" -    files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: ")) -    files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name +    proposed_files_name = "#{name}_files.json" +    files_name = get_option(opts, :files, "Save file list to:", proposed_files_name)      default_exts = [".png", ".gif"] -    default_exts_str = Enum.join(default_exts, " ") -    exts = -      String.trim( -        IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ") +    custom_exts = +      get_option( +        opts, +        :extensions, +        "Emoji file extensions (separated with spaces):", +        Enum.join(default_exts, " ")        ) +      |> String.split(" ", trim: true)      exts = -      if String.length(exts) > 0 do -        String.split(exts, " ") -        |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end) -      else +      if MapSet.equal?(MapSet.new(default_exts), MapSet.new(custom_exts)) do          default_exts +      else +        custom_exts        end +    IO.puts("Using #{Enum.join(exts, " ")} extensions") +      IO.puts("Downloading the pack and generating SHA256")      binary_archive = Tesla.get!(client(), src).body @@ -184,11 +201,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do      tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}") -    {:ok, _} = -      :zip.unzip( -        binary_archive, -        cwd: tmp_pack_dir -      ) +    {:ok, _} = :zip.unzip(binary_archive, cwd: String.to_charlist(tmp_pack_dir))      emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts) @@ -197,14 +210,16 @@ defmodule Mix.Tasks.Pleroma.Emoji do      IO.puts("""      #{files_name} has been created and contains the list of all found emojis in the pack. -    Please review the files in the remove those not needed. +    Please review the files in the pack and remove those not needed.      """) -    if File.exists?("index.json") do -      existing_data = File.read!("index.json") |> Jason.decode!() +    pack_file = "#{name}.json" + +    if File.exists?(pack_file) do +      existing_data = File.read!(pack_file) |> Jason.decode!()        File.write!( -        "index.json", +        pack_file,          Jason.encode!(            Map.merge(              existing_data, @@ -214,11 +229,11 @@ defmodule Mix.Tasks.Pleroma.Emoji do          )        ) -      IO.puts("index.json file has been update with the #{name} pack") +      IO.puts("#{pack_file} has been updated with the #{name} pack")      else -      File.write!("index.json", Jason.encode!(pack_json, pretty: true)) +      File.write!(pack_file, Jason.encode!(pack_json, pretty: true)) -      IO.puts("index.json has been created with the #{name} pack") +      IO.puts("#{pack_file} has been created with the #{name} pack")      end    end diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 9af6cda30..bc842a59f 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -1,11 +1,13 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Instance do    use Mix.Task    import Mix.Pleroma +  alias Pleroma.Config +    @shortdoc "Manages Pleroma instance"    @moduledoc File.read!("docs/administration/CLI_tasks/instance.md") @@ -63,7 +65,8 @@ defmodule Mix.Tasks.Pleroma.Instance do          get_option(            options,            :instance_name, -          "What is the name of your instance? (e.g. Pleroma/Soykaf)" +          "What is the name of your instance? (e.g. The Corndog Emporium)", +          domain          )        email = get_option(options, :admin_email, "What is your admin email address?") @@ -153,6 +156,8 @@ defmodule Mix.Tasks.Pleroma.Instance do            Pleroma.Config.get([:instance, :static_dir])          ) +      Config.put([:instance, :static_dir], static_dir) +        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) @@ -202,8 +207,14 @@ defmodule Mix.Tasks.Pleroma.Instance do        write_robots_txt(indexable, template_dir)        shell_info( -        "\n All files successfully written! Refer to the installation instructions for your platform for next steps" +        "\n All files successfully written! Refer to the installation instructions for your platform for next steps."        ) + +      if db_configurable? do +        shell_info( +          " Please transfer your config to the database after running database migrations. Refer to \"Transfering the config to/from the database\" section of the docs for more information." +        ) +      end      else        shell_error(          "The task would have overwritten the following files:\n" <> diff --git a/lib/mix/tasks/pleroma/notification_settings.ex b/lib/mix/tasks/pleroma/notification_settings.ex new file mode 100644 index 000000000..7d65f0587 --- /dev/null +++ b/lib/mix/tasks/pleroma/notification_settings.ex @@ -0,0 +1,83 @@ +defmodule Mix.Tasks.Pleroma.NotificationSettings do +  @shortdoc "Enable&Disable privacy option for push notifications" +  @moduledoc """ +  Example: + +  > mix pleroma.notification_settings --privacy-option=false --nickname-users="parallel588"  # set false only for parallel588 user +  > mix pleroma.notification_settings --privacy-option=true # set true for all users + +  """ + +  use Mix.Task +  import Mix.Pleroma +  import Ecto.Query + +  def run(args) do +    start_pleroma() + +    {options, _, _} = +      OptionParser.parse( +        args, +        strict: [ +          privacy_option: :boolean, +          email_users: :string, +          nickname_users: :string +        ] +      ) + +    privacy_option = Keyword.get(options, :privacy_option) + +    if not is_nil(privacy_option) do +      privacy_option +      |> build_query(options) +      |> Pleroma.Repo.update_all([]) +    end + +    shell_info("Done") +  end + +  defp build_query(privacy_option, options) do +    query = +      from(u in Pleroma.User, +        update: [ +          set: [ +            notification_settings: +              fragment( +                "jsonb_set(notification_settings, '{privacy_option}', ?)", +                ^privacy_option +              ) +          ] +        ] +      ) + +    user_emails = +      options +      |> Keyword.get(:email_users, "") +      |> String.split(",") +      |> Enum.map(&String.trim(&1)) +      |> Enum.reject(&(&1 == "")) + +    query = +      if length(user_emails) > 0 do +        where(query, [u], u.email in ^user_emails) +      else +        query +      end + +    user_nicknames = +      options +      |> Keyword.get(:nickname_users, "") +      |> String.split(",") +      |> Enum.map(&String.trim(&1)) +      |> Enum.reject(&(&1 == "")) + +    query = +      if length(user_nicknames) > 0 do +        where(query, [u], u.nickname in ^user_nicknames) +      else +        query +      end + +    query +  end +end diff --git a/lib/mix/tasks/pleroma/refresh_counter_cache.ex b/lib/mix/tasks/pleroma/refresh_counter_cache.ex new file mode 100644 index 000000000..15b4dbfa6 --- /dev/null +++ b/lib/mix/tasks/pleroma/refresh_counter_cache.ex @@ -0,0 +1,46 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.RefreshCounterCache do +  @shortdoc "Refreshes counter cache" + +  use Mix.Task + +  alias Pleroma.Activity +  alias Pleroma.CounterCache +  alias Pleroma.Repo + +  require Logger +  import Ecto.Query + +  def run([]) do +    Mix.Pleroma.start_pleroma() + +    ["public", "unlisted", "private", "direct"] +    |> Enum.each(fn visibility -> +      count = status_visibility_count_query(visibility) +      name = "status_visibility_#{visibility}" +      CounterCache.set(name, count) +      Mix.Pleroma.shell_info("Set #{name} to #{count}") +    end) + +    Mix.Pleroma.shell_info("Done") +  end + +  defp status_visibility_count_query(visibility) do +    Activity +    |> where( +      [a], +      fragment( +        "activity_visibility(?, ?, ?) = ?", +        a.actor, +        a.recipients, +        a.data, +        ^visibility +      ) +    ) +    |> where([a], fragment("(? ->> 'type'::text) = 'Create'", a.data)) +    |> Repo.aggregate(:count, :id, timeout: :timer.minutes(30)) +  end +end diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex index 7ef5f9678..c3312507e 100644 --- a/lib/mix/tasks/pleroma/relay.ex +++ b/lib/mix/tasks/pleroma/relay.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Relay do @@ -35,7 +35,7 @@ defmodule Mix.Tasks.Pleroma.Relay do    def run(["list"]) do      start_pleroma() -    with {:ok, list} <- Relay.list() do +    with {:ok, list} <- Relay.list(true) do        list |> Enum.each(&shell_info(&1))      else        {:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}") diff --git a/lib/mix/tasks/pleroma/robotstxt.ex b/lib/mix/tasks/pleroma/robotstxt.ex index 2128e1cd6..24f08180e 100644 --- a/lib/mix/tasks/pleroma/robotstxt.ex +++ b/lib/mix/tasks/pleroma/robotstxt.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.RobotsTxt do @@ -18,6 +18,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do    """    def run(["disallow_all"]) do +    Mix.Pleroma.start_pleroma()      static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")      if !File.exists?(static_dir) do diff --git a/lib/mix/tasks/pleroma/uploads.ex b/lib/mix/tasks/pleroma/uploads.ex index 3e6fc7ee0..c47b7531e 100644 --- a/lib/mix/tasks/pleroma/uploads.ex +++ b/lib/mix/tasks/pleroma/uploads.ex @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.Uploads do diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 134b5bccc..da140ac86 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -1,13 +1,15 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Mix.Tasks.Pleroma.User do    use Mix.Task    import Mix.Pleroma +  alias Ecto.Changeset    alias Pleroma.User    alias Pleroma.UserInviteToken -  alias Pleroma.Web.OAuth +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.Pipeline    @shortdoc "Manages Pleroma users"    @moduledoc File.read!("docs/administration/CLI_tasks/user.md") @@ -96,12 +98,12 @@ defmodule Mix.Tasks.Pleroma.User do    def run(["rm", nickname]) do      start_pleroma() -    with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do -      User.perform(:delete, user) +    with %User{local: true} = user <- User.get_cached_by_nickname(nickname), +         {:ok, delete_data, _} <- Builder.delete(user, user.ap_id), +         {:ok, _delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do        shell_info("User #{nickname} deleted.")      else -      _ -> -        shell_error("No local user #{nickname}") +      _ -> shell_error("No local user #{nickname}")      end    end @@ -109,10 +111,10 @@ defmodule Mix.Tasks.Pleroma.User do      start_pleroma()      with %User{} = user <- User.get_cached_by_nickname(nickname) do -      {:ok, user} = User.deactivate(user, !user.info.deactivated) +      {:ok, user} = User.deactivate(user, !user.deactivated)        shell_info( -        "Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated" +        "Activation status of #{nickname}: #{if(user.deactivated, do: "de", else: "")}activated"        )      else        _ -> @@ -162,7 +164,7 @@ defmodule Mix.Tasks.Pleroma.User do        user = User.get_cached_by_id(user.id) -      if Enum.empty?(user.following) do +      if Enum.empty?(User.get_friends(user)) do          shell_info("Successfully unsubscribed all followers from #{user.nickname}")        end      else @@ -340,7 +342,7 @@ defmodule Mix.Tasks.Pleroma.User do      with %User{} = user <- User.get_cached_by_nickname(nickname) do        {:ok, user} = User.toggle_confirmation(user) -      message = if user.info.confirmation_pending, do: "needs", else: "doesn't need" +      message = if user.confirmation_pending, do: "needs", else: "doesn't need"        shell_info("#{nickname} #{message} confirmation.")      else @@ -353,8 +355,7 @@ defmodule Mix.Tasks.Pleroma.User do      start_pleroma()      with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do -      OAuth.Token.delete_user_tokens(user) -      OAuth.Authorization.delete_user_authorizations(user) +      User.global_sign_out(user)        shell_info("#{nickname} signed out from all apps.")      else @@ -363,24 +364,48 @@ defmodule Mix.Tasks.Pleroma.User do      end    end +  def run(["list"]) do +    start_pleroma() + +    Pleroma.User.Query.build(%{local: true}) +    |> Pleroma.RepoStreamer.chunk_stream(500) +    |> Stream.each(fn users -> +      users +      |> Enum.each(fn user -> +        shell_info( +          "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{ +            user.locked +          }, deactivated: #{user.deactivated}" +        ) +      end) +    end) +    |> Stream.run() +  end +    defp set_moderator(user, value) do -    {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_moderator: value})) +    {:ok, user} = +      user +      |> Changeset.change(%{is_moderator: value}) +      |> User.update_and_set_cache() -    shell_info("Moderator status of #{user.nickname}: #{user.info.is_moderator}") +    shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}")      user    end    defp set_admin(user, value) do -    {:ok, user} = User.update_info(user, &User.Info.admin_api_update(&1, %{is_admin: value})) +    {:ok, user} = User.admin_api_update(user, %{is_admin: value}) -    shell_info("Admin status of #{user.nickname}: #{user.info.is_admin}") +    shell_info("Admin status of #{user.nickname}: #{user.is_admin}")      user    end    defp set_locked(user, value) do -    {:ok, user} = User.update_info(user, &User.Info.user_upgrade(&1, %{locked: value})) +    {:ok, user} = +      user +      |> Changeset.change(%{locked: value}) +      |> User.update_and_set_cache() -    shell_info("Locked status of #{user.nickname}: #{user.info.locked}") +    shell_info("Locked status of #{user.nickname}: #{user.locked}")      user    end  end | 
