Merge branch 'develop' into feature/database-compaction
This commit is contained in:
commit
627e5a0a49
1271 changed files with 42114 additions and 70683 deletions
|
|
@ -6,9 +6,9 @@ defmodule Mix.Tasks.CompactDatabase do
|
|||
require Logger
|
||||
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
import Ecto.Query
|
||||
alias Pleroma.{Repo, Object, Activity}
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Repo
|
||||
|
||||
defp maybe_compact(%Activity{data: %{"object" => %{"id" => object_id}}} = activity) do
|
||||
data =
|
||||
|
|
@ -33,7 +33,7 @@ defmodule Mix.Tasks.CompactDatabase do
|
|||
)
|
||||
end
|
||||
|
||||
def run(args) do
|
||||
def run(_args) do
|
||||
Application.ensure_all_started(:pleroma)
|
||||
|
||||
max = Repo.aggregate(Activity, :max, :id)
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
defmodule Mix.Tasks.DeactivateUser do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@moduledoc """
|
||||
Deactivates a user (local or remote)
|
||||
|
||||
Usage: ``mix deactivate_user <nickname>``
|
||||
|
||||
Example: ``mix deactivate_user lain``
|
||||
"""
|
||||
def run([nickname]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with user <- User.get_by_nickname(nickname) do
|
||||
User.deactivate(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
defmodule Mix.Tasks.GenerateConfig do
|
||||
use Mix.Task
|
||||
|
||||
@moduledoc """
|
||||
Generate a new config
|
||||
|
||||
## Usage
|
||||
``mix generate_config``
|
||||
|
||||
This mix task is interactive, and will overwrite the config present at ``config/generated_config.exs``.
|
||||
"""
|
||||
|
||||
def run(_) do
|
||||
IO.puts("Answer a few questions to generate a new config\n")
|
||||
IO.puts("--- THIS WILL OVERWRITE YOUR config/generated_config.exs! ---\n")
|
||||
domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim()
|
||||
name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim()
|
||||
email = IO.gets("What's your admin email address: ") |> String.trim()
|
||||
|
||||
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||
dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||
|
||||
resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", dbpass: dbpass)
|
||||
|
||||
result =
|
||||
EEx.eval_file(
|
||||
"lib/mix/tasks/sample_config.eex",
|
||||
domain: domain,
|
||||
email: email,
|
||||
name: name,
|
||||
secret: secret,
|
||||
dbpass: dbpass
|
||||
)
|
||||
|
||||
IO.puts(
|
||||
"\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs"
|
||||
)
|
||||
|
||||
File.write("config/generated_config.exs", result)
|
||||
|
||||
IO.puts(
|
||||
"\nWriting setup_db.psql, please run it as postgre superuser, i.e.: sudo su postgres -c 'psql -f config/setup_db.psql'"
|
||||
)
|
||||
|
||||
File.write("config/setup_db.psql", resultSql)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
defmodule Mix.Tasks.GenerateInviteToken do
|
||||
use Mix.Task
|
||||
|
||||
@moduledoc """
|
||||
Generates invite token
|
||||
|
||||
This is in the form of a URL to be used by the Invited user to register themselves.
|
||||
|
||||
## Usage
|
||||
``mix generate_invite_token``
|
||||
"""
|
||||
def run([]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with {:ok, token} <- Pleroma.UserInviteToken.create_token() do
|
||||
IO.puts("Generated user invite token")
|
||||
|
||||
IO.puts(
|
||||
"Url: #{
|
||||
Pleroma.Web.Router.Helpers.redirect_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
:registration_page,
|
||||
token.token
|
||||
)
|
||||
}"
|
||||
)
|
||||
else
|
||||
_ ->
|
||||
IO.puts("Error creating token")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
defmodule Mix.Tasks.GeneratePasswordReset do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@moduledoc """
|
||||
Generate password reset link for user
|
||||
|
||||
Usage: ``mix generate_password_reset <nickname>``
|
||||
|
||||
Example: ``mix generate_password_reset lain``
|
||||
"""
|
||||
def run([nickname]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname),
|
||||
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||
IO.puts("Generated password reset token for #{user.nickname}")
|
||||
|
||||
IO.puts(
|
||||
"Url: #{
|
||||
Pleroma.Web.Router.Helpers.util_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
:show_password_reset,
|
||||
token.token
|
||||
)
|
||||
}"
|
||||
)
|
||||
else
|
||||
_ ->
|
||||
IO.puts("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
defmodule Mix.Tasks.SetModerator do
|
||||
@moduledoc """
|
||||
Set moderator to a local user
|
||||
|
||||
Usage: ``mix set_moderator <nickname>``
|
||||
|
||||
Example: ``mix set_moderator lain``
|
||||
"""
|
||||
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
def run([nickname | rest]) do
|
||||
Application.ensure_all_started(:pleroma)
|
||||
|
||||
moderator =
|
||||
case rest do
|
||||
[moderator] -> moderator == "true"
|
||||
_ -> true
|
||||
end
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("is_moderator", !!moderator)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
IO.puts("Moderator status of #{nickname}: #{user.info["is_moderator"]}")
|
||||
else
|
||||
_ ->
|
||||
IO.puts("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
end
|
||||
28
lib/mix/tasks/pleroma/common.ex
Normal file
28
lib/mix/tasks/pleroma/common.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Common do
|
||||
@doc "Common functions to be reused in mix tasks"
|
||||
def start_pleroma do
|
||||
Mix.Task.run("app.start")
|
||||
end
|
||||
|
||||
def get_option(options, opt, prompt, defval \\ nil, defname \\ nil) do
|
||||
Keyword.get(options, opt) ||
|
||||
case Mix.shell().prompt("#{prompt} [#{defname || defval}]") do
|
||||
"\n" ->
|
||||
case defval do
|
||||
nil -> get_option(options, opt, prompt, defval)
|
||||
defval -> defval
|
||||
end
|
||||
|
||||
opt ->
|
||||
opt |> String.trim()
|
||||
end
|
||||
end
|
||||
|
||||
def escape_sh_path(path) do
|
||||
~S(') <> String.replace(path, ~S('), ~S(\')) <> ~S(')
|
||||
end
|
||||
end
|
||||
213
lib/mix/tasks/pleroma/instance.ex
Normal file
213
lib/mix/tasks/pleroma/instance.ex
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Instance do
|
||||
use Mix.Task
|
||||
alias Mix.Tasks.Pleroma.Common
|
||||
|
||||
@shortdoc "Manages Pleroma instance"
|
||||
@moduledoc """
|
||||
Manages Pleroma instance.
|
||||
|
||||
## Generate a new instance config.
|
||||
|
||||
mix pleroma.instance gen [OPTION...]
|
||||
|
||||
If any options are left unspecified, you will be prompted interactively
|
||||
|
||||
## Options
|
||||
|
||||
- `-f`, `--force` - overwrite any output files
|
||||
- `-o PATH`, `--output PATH` - the output file for the generated configuration
|
||||
- `--output-psql PATH` - the output file for the generated PostgreSQL setup
|
||||
- `--domain DOMAIN` - the domain of your instance
|
||||
- `--instance-name INSTANCE_NAME` - the name of your instance
|
||||
- `--admin-email ADMIN_EMAIL` - the email address of the instance admin
|
||||
- `--notify-email NOTIFY_EMAIL` - email address for notifications
|
||||
- `--dbhost HOSTNAME` - the hostname of the PostgreSQL database to use
|
||||
- `--dbname DBNAME` - the name of the database to use
|
||||
- `--dbuser DBUSER` - the user (aka role) to use for the database connection
|
||||
- `--dbpass DBPASS` - the password to use for the database connection
|
||||
- `--indexable Y/N` - Allow/disallow indexing site by search engines
|
||||
"""
|
||||
|
||||
def run(["gen" | rest]) do
|
||||
{options, [], []} =
|
||||
OptionParser.parse(
|
||||
rest,
|
||||
strict: [
|
||||
force: :boolean,
|
||||
output: :string,
|
||||
output_psql: :string,
|
||||
domain: :string,
|
||||
instance_name: :string,
|
||||
admin_email: :string,
|
||||
notify_email: :string,
|
||||
dbhost: :string,
|
||||
dbname: :string,
|
||||
dbuser: :string,
|
||||
dbpass: :string,
|
||||
indexable: :string
|
||||
],
|
||||
aliases: [
|
||||
o: :output,
|
||||
f: :force
|
||||
]
|
||||
)
|
||||
|
||||
paths =
|
||||
[config_path, psql_path] = [
|
||||
Keyword.get(options, :output, "config/generated_config.exs"),
|
||||
Keyword.get(options, :output_psql, "config/setup_db.psql")
|
||||
]
|
||||
|
||||
will_overwrite = Enum.filter(paths, &File.exists?/1)
|
||||
proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
|
||||
|
||||
if proceed? do
|
||||
[domain, port | _] =
|
||||
String.split(
|
||||
Common.get_option(
|
||||
options,
|
||||
:domain,
|
||||
"What domain will your instance use? (e.g pleroma.soykaf.com)"
|
||||
),
|
||||
":"
|
||||
) ++ [443]
|
||||
|
||||
name =
|
||||
Common.get_option(
|
||||
options,
|
||||
:instance_name,
|
||||
"What is the name of your instance? (e.g. Pleroma/Soykaf)"
|
||||
)
|
||||
|
||||
email = Common.get_option(options, :admin_email, "What is your admin email address?")
|
||||
|
||||
notify_email =
|
||||
Common.get_option(
|
||||
options,
|
||||
:notify_email,
|
||||
"What email address do you want to use for sending email notifications?",
|
||||
email
|
||||
)
|
||||
|
||||
indexable =
|
||||
Common.get_option(
|
||||
options,
|
||||
:indexable,
|
||||
"Do you want search engines to index your site? (y/n)",
|
||||
"y"
|
||||
) === "y"
|
||||
|
||||
dbhost =
|
||||
Common.get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
|
||||
|
||||
dbname =
|
||||
Common.get_option(options, :dbname, "What is the name of your database?", "pleroma_dev")
|
||||
|
||||
dbuser =
|
||||
Common.get_option(
|
||||
options,
|
||||
:dbuser,
|
||||
"What is the user used to connect to your database?",
|
||||
"pleroma"
|
||||
)
|
||||
|
||||
dbpass =
|
||||
Common.get_option(
|
||||
options,
|
||||
:dbpass,
|
||||
"What is the password used to connect to your database?",
|
||||
:crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64),
|
||||
"autogenerated"
|
||||
)
|
||||
|
||||
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||
signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
|
||||
{web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)
|
||||
|
||||
result_config =
|
||||
EEx.eval_file(
|
||||
"sample_config.eex" |> Path.expand(__DIR__),
|
||||
domain: domain,
|
||||
port: port,
|
||||
email: email,
|
||||
notify_email: notify_email,
|
||||
name: name,
|
||||
dbhost: dbhost,
|
||||
dbname: dbname,
|
||||
dbuser: dbuser,
|
||||
dbpass: dbpass,
|
||||
version: Pleroma.Mixfile.project() |> Keyword.get(:version),
|
||||
secret: secret,
|
||||
signing_salt: signing_salt,
|
||||
web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),
|
||||
web_push_private_key: Base.url_encode64(web_push_private_key, padding: false)
|
||||
)
|
||||
|
||||
result_psql =
|
||||
EEx.eval_file(
|
||||
"sample_psql.eex" |> Path.expand(__DIR__),
|
||||
dbname: dbname,
|
||||
dbuser: dbuser,
|
||||
dbpass: dbpass
|
||||
)
|
||||
|
||||
Mix.shell().info(
|
||||
"Writing config to #{config_path}. You should rename it to config/prod.secret.exs or config/dev.secret.exs."
|
||||
)
|
||||
|
||||
File.write(config_path, result_config)
|
||||
Mix.shell().info("Writing #{psql_path}.")
|
||||
File.write(psql_path, result_psql)
|
||||
|
||||
write_robots_txt(indexable)
|
||||
|
||||
Mix.shell().info(
|
||||
"\n" <>
|
||||
"""
|
||||
To get started:
|
||||
1. Verify the contents of the generated files.
|
||||
2. Run `sudo -u postgres psql -f #{Common.escape_sh_path(psql_path)}`.
|
||||
""" <>
|
||||
if config_path in ["config/dev.secret.exs", "config/prod.secret.exs"] do
|
||||
""
|
||||
else
|
||||
"3. Run `mv #{Common.escape_sh_path(config_path)} 'config/prod.secret.exs'`."
|
||||
end
|
||||
)
|
||||
else
|
||||
Mix.shell().error(
|
||||
"The task would have overwritten the following files:\n" <>
|
||||
(Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <>
|
||||
"Rerun with `--force` to overwrite them."
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp write_robots_txt(indexable) do
|
||||
robots_txt =
|
||||
EEx.eval_file(
|
||||
Path.expand("robots_txt.eex", __DIR__),
|
||||
indexable: indexable
|
||||
)
|
||||
|
||||
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
|
||||
|
||||
unless File.exists?(static_dir) do
|
||||
File.mkdir_p!(static_dir)
|
||||
end
|
||||
|
||||
robots_txt_path = Path.join(static_dir, "robots.txt")
|
||||
|
||||
if File.exists?(robots_txt_path) do
|
||||
File.cp!(robots_txt_path, "#{robots_txt_path}.bak")
|
||||
Mix.shell().info("Backing up existing robots.txt to #{robots_txt_path}.bak")
|
||||
end
|
||||
|
||||
File.write(robots_txt_path, robots_txt)
|
||||
Mix.shell().info("Writing #{robots_txt_path}.")
|
||||
end
|
||||
end
|
||||
47
lib/mix/tasks/pleroma/relay.ex
Normal file
47
lib/mix/tasks/pleroma/relay.ex
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Relay do
|
||||
use Mix.Task
|
||||
alias Mix.Tasks.Pleroma.Common
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
|
||||
@shortdoc "Manages remote relays"
|
||||
@moduledoc """
|
||||
Manages remote relays
|
||||
|
||||
## Follow a remote relay
|
||||
|
||||
``mix pleroma.relay follow <relay_url>``
|
||||
|
||||
Example: ``mix pleroma.relay follow https://example.org/relay``
|
||||
|
||||
## Unfollow a remote relay
|
||||
|
||||
``mix pleroma.relay unfollow <relay_url>``
|
||||
|
||||
Example: ``mix pleroma.relay unfollow https://example.org/relay``
|
||||
"""
|
||||
def run(["follow", target]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with {:ok, _activity} <- Relay.follow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["unfollow", target]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with {:ok, _activity} <- Relay.unfollow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
2
lib/mix/tasks/pleroma/robots_txt.eex
Normal file
2
lib/mix/tasks/pleroma/robots_txt.eex
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
User-Agent: *
|
||||
Disallow: <%= if indexable, do: "", else: "/" %>
|
||||
32
lib/mix/tasks/pleroma/robotstxt.ex
Normal file
32
lib/mix/tasks/pleroma/robotstxt.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
||||
use Mix.Task
|
||||
|
||||
@shortdoc "Generate robots.txt"
|
||||
@moduledoc """
|
||||
Generates robots.txt
|
||||
|
||||
## Overwrite robots.txt to disallow all
|
||||
|
||||
mix pleroma.robots_txt disallow_all
|
||||
|
||||
This will write a robots.txt that will hide all paths on your instance
|
||||
from search engines and other robots that obey robots.txt
|
||||
|
||||
"""
|
||||
def run(["disallow_all"]) do
|
||||
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
|
||||
|
||||
if !File.exists?(static_dir) do
|
||||
File.mkdir_p!(static_dir)
|
||||
end
|
||||
|
||||
robots_txt_path = Path.join(static_dir, "robots.txt")
|
||||
robots_txt_content = "User-Agent: *\nDisallow: /\n"
|
||||
|
||||
File.write!(robots_txt_path, robots_txt_content, [:write])
|
||||
end
|
||||
end
|
||||
|
|
@ -1,12 +1,19 @@
|
|||
# Pleroma instance configuration
|
||||
|
||||
# NOTE: This file should not be committed to a repo or otherwise made public
|
||||
# without removing sensitive information.
|
||||
|
||||
use Mix.Config
|
||||
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "<%= domain %>", scheme: "https", port: 443],
|
||||
secret_key_base: "<%= secret %>"
|
||||
url: [host: "<%= domain %>", scheme: "https", port: <%= port %>],
|
||||
secret_key_base: "<%= secret %>",
|
||||
signing_salt: "<%= signing_salt %>"
|
||||
|
||||
config :pleroma, :instance,
|
||||
name: "<%= name %>",
|
||||
email: "<%= email %>",
|
||||
notify_email: "<%= notify_email %>",
|
||||
limit: 5000,
|
||||
registrations_open: true,
|
||||
dedupe_media: false
|
||||
|
|
@ -16,15 +23,20 @@ config :pleroma, :media_proxy,
|
|||
redirect_on_failure: true
|
||||
#base_url: "https://cache.pleroma.social"
|
||||
|
||||
# Configure your database
|
||||
config :pleroma, Pleroma.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
username: "pleroma",
|
||||
username: "<%= dbuser %>",
|
||||
password: "<%= dbpass %>",
|
||||
database: "pleroma_dev",
|
||||
hostname: "localhost",
|
||||
database: "<%= dbname %>",
|
||||
hostname: "<%= dbhost %>",
|
||||
pool_size: 10
|
||||
|
||||
# Configure web push notifications
|
||||
config :web_push_encryption, :vapid_details,
|
||||
subject: "mailto:<%= email %>",
|
||||
public_key: "<%= web_push_public_key %>",
|
||||
private_key: "<%= web_push_private_key %>"
|
||||
|
||||
# Enable Strict-Transport-Security once SSL is working:
|
||||
# config :pleroma, :http_security,
|
||||
# sts: true
|
||||
|
|
@ -50,9 +62,9 @@ config :pleroma, Pleroma.Repo,
|
|||
|
||||
|
||||
# Configure Openstack Swift support if desired.
|
||||
#
|
||||
# Many openstack deployments are different, so config is left very open with
|
||||
# no assumptions made on which provider you're using. This should allow very
|
||||
#
|
||||
# Many openstack deployments are different, so config is left very open with
|
||||
# no assumptions made on which provider you're using. This should allow very
|
||||
# wide support without needing separate handlers for OVH, Rackspace, etc.
|
||||
#
|
||||
# config :pleroma, Pleroma.Uploaders.Swift,
|
||||
|
|
@ -64,4 +76,3 @@ config :pleroma, Pleroma.Repo,
|
|||
# storage_url: "https://swift-endpoint.prodider.com/v1/AUTH_<tenant>/<container>",
|
||||
# object_url: "https://cdn-endpoint.provider.com/<container>"
|
||||
#
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
CREATE USER pleroma WITH ENCRYPTED PASSWORD '<%= dbpass %>';
|
||||
CREATE DATABASE pleroma_dev OWNER pleroma;
|
||||
\c pleroma_dev;
|
||||
CREATE USER <%= dbuser %> WITH ENCRYPTED PASSWORD '<%= dbpass %>';
|
||||
CREATE DATABASE <%= dbname %> OWNER <%= dbuser %>;
|
||||
\c <%= dbname %>;
|
||||
--Extensions made by ecto.migrate that need superuser access
|
||||
CREATE EXTENSION IF NOT EXISTS citext;
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
|
@ -1,16 +1,30 @@
|
|||
defmodule Mix.Tasks.MigrateLocalUploads do
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Uploads do
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{Upload, Uploaders.Local, Uploaders.S3}
|
||||
alias Mix.Tasks.Pleroma.Common
|
||||
alias Pleroma.Upload
|
||||
alias Pleroma.Uploaders.Local
|
||||
require Logger
|
||||
|
||||
@log_every 50
|
||||
@shortdoc "Migrate uploads from local to remote storage"
|
||||
|
||||
def run([target_uploader | args]) do
|
||||
@shortdoc "Migrates uploads from local to remote storage"
|
||||
@moduledoc """
|
||||
Manages uploads
|
||||
|
||||
## Migrate uploads from local to remote storage
|
||||
mix pleroma.uploads migrate_local TARGET_UPLOADER [OPTIONS...]
|
||||
Options:
|
||||
- `--delete` - delete local uploads after migrating them to the target uploader
|
||||
|
||||
A list of available uploaders can be seen in config.exs
|
||||
"""
|
||||
def run(["migrate_local", target_uploader | args]) do
|
||||
delete? = Enum.member?(args, "--delete")
|
||||
Application.ensure_all_started(:pleroma)
|
||||
|
||||
Common.start_pleroma()
|
||||
local_path = Pleroma.Config.get!([Local, :uploads])
|
||||
uploader = Module.concat(Pleroma.Uploaders, target_uploader)
|
||||
|
||||
|
|
@ -24,10 +38,10 @@ defmodule Mix.Tasks.MigrateLocalUploads do
|
|||
Pleroma.Config.put([Upload, :uploader], uploader)
|
||||
end
|
||||
|
||||
Logger.info("Migrating files from local #{local_path} to #{to_string(uploader)}")
|
||||
Mix.shell().info("Migrating files from local #{local_path} to #{to_string(uploader)}")
|
||||
|
||||
if delete? do
|
||||
Logger.warn(
|
||||
Mix.shell().info(
|
||||
"Attention: uploaded files will be deleted, hope you have backups! (--delete ; cancel with ^C)"
|
||||
)
|
||||
|
||||
|
|
@ -54,7 +68,7 @@ defmodule Mix.Tasks.MigrateLocalUploads do
|
|||
|
||||
File.exists?(root_path) ->
|
||||
file = Path.basename(id)
|
||||
[hash, ext] = String.split(id, ".")
|
||||
hash = Path.rootname(id)
|
||||
{%Pleroma.Upload{id: hash, name: file, path: file, tempfile: root_path}, root_path}
|
||||
|
||||
true ->
|
||||
|
|
@ -64,7 +78,7 @@ defmodule Mix.Tasks.MigrateLocalUploads do
|
|||
|> Enum.filter(& &1)
|
||||
|
||||
total_count = length(uploads)
|
||||
Logger.info("Found #{total_count} uploads")
|
||||
Mix.shell().info("Found #{total_count} uploads")
|
||||
|
||||
uploads
|
||||
|> Task.async_stream(
|
||||
|
|
@ -76,22 +90,19 @@ defmodule Mix.Tasks.MigrateLocalUploads do
|
|||
:ok
|
||||
|
||||
error ->
|
||||
Logger.error("failed to upload #{inspect(upload.path)}: #{inspect(error)}")
|
||||
Mix.shell().error("failed to upload #{inspect(upload.path)}: #{inspect(error)}")
|
||||
end
|
||||
end,
|
||||
timeout: 150_000
|
||||
)
|
||||
|> Stream.chunk_every(@log_every)
|
||||
# credo:disable-for-next-line Credo.Check.Warning.UnusedEnumOperation
|
||||
|> Enum.reduce(0, fn done, count ->
|
||||
count = count + length(done)
|
||||
Logger.info("Uploaded #{count}/#{total_count} files")
|
||||
Mix.shell().info("Uploaded #{count}/#{total_count} files")
|
||||
count
|
||||
end)
|
||||
|
||||
Logger.info("Done!")
|
||||
end
|
||||
|
||||
def run(_) do
|
||||
Logger.error("Usage: migrate_local_uploads S3|Swift [--delete]")
|
||||
Mix.shell().info("Done!")
|
||||
end
|
||||
end
|
||||
429
lib/mix/tasks/pleroma/user.ex
Normal file
429
lib/mix/tasks/pleroma/user.ex
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.User do
|
||||
use Mix.Task
|
||||
import Ecto.Changeset
|
||||
alias Mix.Tasks.Pleroma.Common
|
||||
alias Pleroma.User
|
||||
alias Pleroma.UserInviteToken
|
||||
|
||||
@shortdoc "Manages Pleroma users"
|
||||
@moduledoc """
|
||||
Manages Pleroma users.
|
||||
|
||||
## Create a new user.
|
||||
|
||||
mix pleroma.user new NICKNAME EMAIL [OPTION...]
|
||||
|
||||
Options:
|
||||
- `--name NAME` - the user's name (i.e., "Lain Iwakura")
|
||||
- `--bio BIO` - the user's bio
|
||||
- `--password PASSWORD` - the user's password
|
||||
- `--moderator`/`--no-moderator` - whether the user is a moderator
|
||||
- `--admin`/`--no-admin` - whether the user is an admin
|
||||
- `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
|
||||
|
||||
## Generate an invite link.
|
||||
|
||||
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
|
||||
|
||||
## List generated invites
|
||||
|
||||
mix pleroma.user invites
|
||||
|
||||
## Revoke invite
|
||||
|
||||
mix pleroma.user revoke_invite TOKEN OR TOKEN_ID
|
||||
|
||||
## Delete the user's account.
|
||||
|
||||
mix pleroma.user rm NICKNAME
|
||||
|
||||
## Delete the user's activities.
|
||||
|
||||
mix pleroma.user delete_activities NICKNAME
|
||||
|
||||
## Deactivate or activate the user's account.
|
||||
|
||||
mix pleroma.user toggle_activated NICKNAME
|
||||
|
||||
## Unsubscribe local users from user's account and deactivate it
|
||||
|
||||
mix pleroma.user unsubscribe NICKNAME
|
||||
|
||||
## Create a password reset link.
|
||||
|
||||
mix pleroma.user reset_password NICKNAME
|
||||
|
||||
## Set the value of the given user's settings.
|
||||
|
||||
mix pleroma.user set NICKNAME [OPTION...]
|
||||
|
||||
Options:
|
||||
- `--locked`/`--no-locked` - whether the user's account is locked
|
||||
- `--moderator`/`--no-moderator` - whether the user is a moderator
|
||||
- `--admin`/`--no-admin` - whether the user is an admin
|
||||
|
||||
## Add tags to a user.
|
||||
|
||||
mix pleroma.user tag NICKNAME TAGS
|
||||
|
||||
## Delete tags from a user.
|
||||
|
||||
mix pleroma.user untag NICKNAME TAGS
|
||||
"""
|
||||
def run(["new", nickname, email | rest]) do
|
||||
{options, [], []} =
|
||||
OptionParser.parse(
|
||||
rest,
|
||||
strict: [
|
||||
name: :string,
|
||||
bio: :string,
|
||||
password: :string,
|
||||
moderator: :boolean,
|
||||
admin: :boolean,
|
||||
assume_yes: :boolean
|
||||
],
|
||||
aliases: [
|
||||
y: :assume_yes
|
||||
]
|
||||
)
|
||||
|
||||
name = Keyword.get(options, :name, nickname)
|
||||
bio = Keyword.get(options, :bio, "")
|
||||
|
||||
{password, generated_password?} =
|
||||
case Keyword.get(options, :password) do
|
||||
nil ->
|
||||
{:crypto.strong_rand_bytes(16) |> Base.encode64(), true}
|
||||
|
||||
password ->
|
||||
{password, false}
|
||||
end
|
||||
|
||||
moderator? = Keyword.get(options, :moderator, false)
|
||||
admin? = Keyword.get(options, :admin, false)
|
||||
assume_yes? = Keyword.get(options, :assume_yes, false)
|
||||
|
||||
Mix.shell().info("""
|
||||
A user will be created with the following information:
|
||||
- nickname: #{nickname}
|
||||
- email: #{email}
|
||||
- password: #{
|
||||
if(generated_password?, do: "[generated; a reset link will be created]", else: password)
|
||||
}
|
||||
- name: #{name}
|
||||
- bio: #{bio}
|
||||
- moderator: #{if(moderator?, do: "true", else: "false")}
|
||||
- admin: #{if(admin?, do: "true", else: "false")}
|
||||
""")
|
||||
|
||||
proceed? = assume_yes? or Mix.shell().yes?("Continue?")
|
||||
|
||||
unless not proceed? do
|
||||
Common.start_pleroma()
|
||||
|
||||
params = %{
|
||||
nickname: nickname,
|
||||
email: email,
|
||||
password: password,
|
||||
password_confirmation: password,
|
||||
name: name,
|
||||
bio: bio
|
||||
}
|
||||
|
||||
changeset = User.register_changeset(%User{}, params, confirmed: true)
|
||||
{:ok, _user} = User.register(changeset)
|
||||
|
||||
Mix.shell().info("User #{nickname} created")
|
||||
|
||||
if moderator? do
|
||||
run(["set", nickname, "--moderator"])
|
||||
end
|
||||
|
||||
if admin? do
|
||||
run(["set", nickname, "--admin"])
|
||||
end
|
||||
|
||||
if generated_password? do
|
||||
run(["reset_password", nickname])
|
||||
end
|
||||
else
|
||||
Mix.shell().info("User will not be created.")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["rm", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
User.delete(user)
|
||||
Mix.shell().info("User #{nickname} deleted.")
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["toggle_activated", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{} = user <- User.get_by_nickname(nickname) do
|
||||
{:ok, user} = User.deactivate(user, !user.info.deactivated)
|
||||
|
||||
Mix.shell().info(
|
||||
"Activation status of #{nickname}: #{if(user.info.deactivated, do: "de", else: "")}activated"
|
||||
)
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["reset_password", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname),
|
||||
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||
Mix.shell().info("Generated password reset token for #{user.nickname}")
|
||||
|
||||
IO.puts(
|
||||
"URL: #{
|
||||
Pleroma.Web.Router.Helpers.util_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
:show_password_reset,
|
||||
token.token
|
||||
)
|
||||
}"
|
||||
)
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["unsubscribe", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{} = user <- User.get_by_nickname(nickname) do
|
||||
Mix.shell().info("Deactivating #{user.nickname}")
|
||||
User.deactivate(user)
|
||||
|
||||
{:ok, friends} = User.get_friends(user)
|
||||
|
||||
Enum.each(friends, fn friend ->
|
||||
user = User.get_by_id(user.id)
|
||||
|
||||
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
|
||||
User.unfollow(user, friend)
|
||||
end)
|
||||
|
||||
:timer.sleep(500)
|
||||
|
||||
user = User.get_by_id(user.id)
|
||||
|
||||
if Enum.empty?(user.following) do
|
||||
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
|
||||
end
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["set", nickname | rest]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
{options, [], []} =
|
||||
OptionParser.parse(
|
||||
rest,
|
||||
strict: [
|
||||
moderator: :boolean,
|
||||
admin: :boolean,
|
||||
locked: :boolean
|
||||
]
|
||||
)
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
user =
|
||||
case Keyword.get(options, :moderator) do
|
||||
nil -> user
|
||||
value -> set_moderator(user, value)
|
||||
end
|
||||
|
||||
user =
|
||||
case Keyword.get(options, :locked) do
|
||||
nil -> user
|
||||
value -> set_locked(user, value)
|
||||
end
|
||||
|
||||
_user =
|
||||
case Keyword.get(options, :admin) do
|
||||
nil -> user
|
||||
value -> set_admin(user, value)
|
||||
end
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["tag", nickname | tags]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{} = user <- User.get_by_nickname(nickname) do
|
||||
user = user |> User.tag(tags)
|
||||
|
||||
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}")
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("Could not change user tags for #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["untag", nickname | tags]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{} = user <- User.get_by_nickname(nickname) do
|
||||
user = user |> User.untag(tags)
|
||||
|
||||
Mix.shell().info("Tags of #{user.nickname}: #{inspect(tags)}")
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("Could not change user tags for #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["invite" | rest]) do
|
||||
{options, [], []} =
|
||||
OptionParser.parse(rest,
|
||||
strict: [
|
||||
expires_at: :string,
|
||||
max_use: :integer
|
||||
]
|
||||
)
|
||||
|
||||
options =
|
||||
options
|
||||
|> Keyword.update(:expires_at, {:ok, nil}, fn
|
||||
nil -> {:ok, nil}
|
||||
val -> Date.from_iso8601(val)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
Common.start_pleroma()
|
||||
|
||||
with {:ok, val} <- options[:expires_at],
|
||||
options = Map.put(options, :expires_at, val),
|
||||
{:ok, invite} <- UserInviteToken.create_invite(options) do
|
||||
Mix.shell().info(
|
||||
"Generated user invite token " <> String.replace(invite.invite_type, "_", " ")
|
||||
)
|
||||
|
||||
url =
|
||||
Pleroma.Web.Router.Helpers.redirect_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
:registration_page,
|
||||
invite.token
|
||||
)
|
||||
|
||||
IO.puts(url)
|
||||
else
|
||||
error ->
|
||||
Mix.shell().error("Could not create invite token: #{inspect(error)}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["invites"]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
Mix.shell().info("Invites list:")
|
||||
|
||||
UserInviteToken.list_invites()
|
||||
|> Enum.each(fn invite ->
|
||||
expire_info =
|
||||
with expires_at when not is_nil(expires_at) <- invite.expires_at do
|
||||
" | Expires at: #{Date.to_string(expires_at)}"
|
||||
end
|
||||
|
||||
using_info =
|
||||
with max_use when not is_nil(max_use) <- invite.max_use do
|
||||
" | Max use: #{max_use} Left use: #{max_use - invite.uses}"
|
||||
end
|
||||
|
||||
Mix.shell().info(
|
||||
"ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
|
||||
invite.used
|
||||
}#{expire_info}#{using_info}"
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
def run(["revoke_invite", token]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with {:ok, invite} <- UserInviteToken.find_by_token(token),
|
||||
{:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do
|
||||
Mix.shell().info("Invite for token #{token} was revoked.")
|
||||
else
|
||||
_ -> Mix.shell().error("No invite found with token #{token}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["delete_activities", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
User.delete_user_activities(user)
|
||||
Mix.shell().info("User #{nickname} statuses deleted.")
|
||||
else
|
||||
_ ->
|
||||
Mix.shell().error("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
defp set_moderator(user, value) do
|
||||
info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value})
|
||||
|
||||
user_cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> put_embed(:info, info_cng)
|
||||
|
||||
{:ok, user} = User.update_and_set_cache(user_cng)
|
||||
|
||||
Mix.shell().info("Moderator status of #{user.nickname}: #{user.info.is_moderator}")
|
||||
user
|
||||
end
|
||||
|
||||
defp set_admin(user, value) do
|
||||
info_cng = User.Info.admin_api_update(user.info, %{is_admin: value})
|
||||
|
||||
user_cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> put_embed(:info, info_cng)
|
||||
|
||||
{:ok, user} = User.update_and_set_cache(user_cng)
|
||||
|
||||
Mix.shell().info("Admin status of #{user.nickname}: #{user.info.is_admin}")
|
||||
user
|
||||
end
|
||||
|
||||
defp set_locked(user, value) do
|
||||
info_cng = User.Info.user_upgrade(user.info, %{locked: value})
|
||||
|
||||
user_cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> put_embed(:info, info_cng)
|
||||
|
||||
{:ok, user} = User.update_and_set_cache(user_cng)
|
||||
|
||||
Mix.shell().info("Locked status of #{user.nickname}: #{user.info.locked}")
|
||||
user
|
||||
end
|
||||
end
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
defmodule Mix.Tasks.ReactivateUser do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@moduledoc """
|
||||
Reactivate a user
|
||||
|
||||
Usage: ``mix reactivate_user <nickname>``
|
||||
|
||||
Example: ``mix reactivate_user lain``
|
||||
"""
|
||||
def run([nickname]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with user <- User.get_by_nickname(nickname) do
|
||||
User.deactivate(user, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
defmodule Mix.Tasks.RegisterUser do
|
||||
@moduledoc """
|
||||
Manually register a local user
|
||||
|
||||
Usage: ``mix register_user <name> <nickname> <email> <bio> <password>``
|
||||
|
||||
Example: ``mix register_user 仮面の告白 lain lain@example.org "blushy-crushy fediverse idol + pleroma dev" pleaseDontHeckLain``
|
||||
"""
|
||||
|
||||
use Mix.Task
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
@shortdoc "Register user"
|
||||
def run([name, nickname, email, bio, password]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
params = %{
|
||||
name: name,
|
||||
nickname: nickname,
|
||||
email: email,
|
||||
password: password,
|
||||
password_confirmation: password,
|
||||
bio: bio
|
||||
}
|
||||
|
||||
user = User.register_changeset(%User{}, params)
|
||||
|
||||
Repo.insert!(user)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
defmodule Mix.Tasks.RelayFollow do
|
||||
use Mix.Task
|
||||
require Logger
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
|
||||
@shortdoc "Follows a remote relay"
|
||||
@moduledoc """
|
||||
Follows a remote relay
|
||||
|
||||
Usage: ``mix relay_follow <relay_url>``
|
||||
|
||||
Example: ``mix relay_follow https://example.org/relay``
|
||||
"""
|
||||
def run([target]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with {:ok, activity} <- Relay.follow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
defmodule Mix.Tasks.RelayUnfollow do
|
||||
use Mix.Task
|
||||
require Logger
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
|
||||
@moduledoc """
|
||||
Unfollows a remote relay
|
||||
|
||||
Usage: ``mix relay_follow <relay_url>``
|
||||
|
||||
Example: ``mix relay_follow https://example.org/relay``
|
||||
"""
|
||||
def run([target]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with {:ok, activity} <- Relay.follow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
defmodule Mix.Tasks.RmUser do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@moduledoc """
|
||||
Permanently deletes a user
|
||||
|
||||
Usage: ``mix rm_user [nickname]``
|
||||
|
||||
Example: ``mix rm_user lain``
|
||||
"""
|
||||
def run([nickname]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
{:ok, _} = User.delete(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
defmodule Mix.Tasks.SetAdmin do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@doc """
|
||||
Sets admin status
|
||||
Usage: set_admin nickname [true|false]
|
||||
"""
|
||||
def run([nickname | rest]) do
|
||||
Application.ensure_all_started(:pleroma)
|
||||
|
||||
status =
|
||||
case rest do
|
||||
[status] -> status == "true"
|
||||
_ -> true
|
||||
end
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("is_admin", !!status)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
IO.puts("Admin status of #{nickname}: #{user.info["is_admin"]}")
|
||||
else
|
||||
_ ->
|
||||
IO.puts("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
defmodule Mix.Tasks.SetLocked do
|
||||
@moduledoc """
|
||||
Lock a local user
|
||||
|
||||
The local user will then have to manually accept/reject followers. This can also be done by the user into their settings.
|
||||
|
||||
Usage: ``mix set_locked <username>``
|
||||
|
||||
Example: ``mix set_locked lain``
|
||||
"""
|
||||
|
||||
use Mix.Task
|
||||
import Mix.Ecto
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
def run([nickname | rest]) do
|
||||
ensure_started(Repo, [])
|
||||
|
||||
locked =
|
||||
case rest do
|
||||
[locked] -> locked == "true"
|
||||
_ -> true
|
||||
end
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("locked", !!locked)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
user = Repo.update!(cng)
|
||||
|
||||
IO.puts("locked status of #{nickname}: #{user.info["locked"]}")
|
||||
else
|
||||
_ ->
|
||||
IO.puts("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
defmodule Mix.Tasks.UnsubscribeUser do
|
||||
use Mix.Task
|
||||
alias Pleroma.{User, Repo}
|
||||
require Logger
|
||||
|
||||
@moduledoc """
|
||||
Deactivate and Unsubscribe local users from a user
|
||||
|
||||
Usage: ``mix unsubscribe_user <nickname>``
|
||||
|
||||
Example: ``mix unsubscribe_user lain``
|
||||
"""
|
||||
def run([nickname]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
with %User{} = user <- User.get_by_nickname(nickname) do
|
||||
Logger.info("Deactivating #{user.nickname}")
|
||||
User.deactivate(user)
|
||||
|
||||
{:ok, friends} = User.get_friends(user)
|
||||
|
||||
Enum.each(friends, fn friend ->
|
||||
user = Repo.get(User, user.id)
|
||||
|
||||
Logger.info("Unsubscribing #{friend.nickname} from #{user.nickname}")
|
||||
User.unfollow(user, friend)
|
||||
end)
|
||||
|
||||
:timer.sleep(500)
|
||||
|
||||
user = Repo.get(User, user.id)
|
||||
|
||||
if length(user.following) == 0 do
|
||||
Logger.info("Successfully unsubscribed all followers from #{user.nickname}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue