New generate config task from Pleroma upstream & move tasks namespace

Little fixes and tests

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2019-01-03 11:34:31 +01:00
parent 6885c73aa8
commit 8d943f950f
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
10 changed files with 229 additions and 149 deletions

View file

@ -1,121 +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 environment file present at ``.env.production``.
Inspired from Pleroma own generate_config task
"""
def run(_) do
IO.puts("Answer a few questions to generate a new config\n")
override =
if File.exists?(".env.production") do
confirm("You already have an .env.production file, do you want to override it?")
else
nil
end
if override == true do
IO.puts("\n--- THIS WILL OVERWRITE YOUR .env.production file! ---\n")
end
if override != false do
domain = string_required("What is your domain name? (e.g. framameet.org): ")
name = string_required("What is the name of your instance? (e.g. Framameet): ")
email = email("What's your admin email address: ")
if confirm("Is everything okay?") do
do_generate(domain, name, email)
else
IO.puts("\nYou cancelled installation\n")
end
else
IO.puts("\nYou cancelled installation\n")
end
end
defp do_generate(domain, name, email) do
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
# Try to avoid issues with some special caracters using url_encode64()
dbpass = :crypto.strong_rand_bytes(64) |> Base.url_encode64() |> binary_part(0, 64)
resultSql = EEx.eval_file("support/postgresql/setup_db.psql", database_password: dbpass)
result =
EEx.eval_file(
".env.production.sample",
instance_domain: domain,
instance_name: name,
instance_email: email,
instance_secret: secret,
database_password: dbpass
)
IO.puts("\nWriting config to .env.production.\n\nCheck it and configure your database.")
File.write(".env.production", result)
IO.puts("""
\nWriting setup_db.psql, please run it as postgres superuser, i.e.: sudo su postgres -c 'psql -f setup_db.psql'\n
You may delete the setup_db.psql file once it has been executed.
""")
File.write("setup_db.psql", resultSql)
end
# Taken from ex_prompt
@spec confirm(String.t()) :: boolean()
defp confirm(prompt) do
answer =
String.trim(prompt)
|> Kernel.<>(" [Yn] ")
|> string()
|> String.downcase()
cond do
answer in ~w(yes y) -> true
answer in ~w(no n) -> false
true -> confirm(prompt)
end
end
# Taken from ex_prompt
@spec string(String.t()) :: String.t()
defp string(prompt) do
case IO.gets(prompt) do
:eof -> ""
{:error, _reason} -> ""
str -> String.trim_trailing(str)
end
end
# Taken from ex_prompt
@spec string_required(String.t()) :: String.t()
defp string_required(prompt) do
case string(prompt) do
"" -> string_required(prompt)
str -> str
end
end
@spec email(String.t(), boolean()) :: String.t()
defp email(prompt, required \\ true) do
email_value =
case required do
true -> string_required(prompt)
_ -> string(prompt)
end
case Mobilizon.Service.EmailChecker.valid?(email_value) do
false -> email(prompt, required)
_ -> email_value
end
end
end

View file

@ -0,0 +1,28 @@
# Portions of this file are derived from Pleroma:
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social>
# SPDX-License-Identifier: AGPL-3.0-only
# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/mix/tasks/pleroma/common.ex
defmodule Mix.Tasks.Mobilizon.Common do
@moduledoc "Common functions to be reused in mix tasks"
def get_option(options, opt, prompt, defval \\ nil, defname \\ nil) do
display = if defname || defval, do: "#{prompt} [#{defname || defval}]", else: "#{prompt}"
Keyword.get(options, opt) ||
case Mix.shell().prompt(display) 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

View file

@ -1,4 +1,4 @@
defmodule Mix.Tasks.CreateBot do defmodule Mix.Tasks.Mobilizon.CreateBot do
@moduledoc """ @moduledoc """
Creates a bot from a source Creates a bot from a source
""" """

View file

@ -0,0 +1,171 @@
# Portions of this file are derived from Pleroma:
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social>
# SPDX-License-Identifier: AGPL-3.0-only
# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/mix/tasks/pleroma/instance.ex
defmodule Mix.Tasks.Mobilizon.Instance do
use Mix.Task
alias Mix.Tasks.Mobilizon.Common
@shortdoc "Generates a new config"
@preferred_cli_env "prod"
@moduledoc """
Generates a new config
## Usage
``mix mobilizon.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
- `--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
"""
def run(["gen" | options]) do
{options, [], []} =
OptionParser.parse(
options,
strict: [
force: :boolean,
output: :string,
output_psql: :string,
domain: :string,
instance_name: :string,
admin_email: :string,
dbhost: :string,
dbname: :string,
dbuser: :string,
dbpass: :string,
dbport: :integer
],
aliases: [
o: :output,
f: :force
]
)
paths =
[config_path, psql_path] = [
Keyword.get(options, :output, ".env"),
Keyword.get(options, :output_psql, "setup_db.psql")
]
will_overwrite = Enum.filter(paths, &File.exists?/1)
proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
unless not proceed? do
[domain, port | _] =
String.split(
Common.get_option(
options,
:domain,
"What domain will your instance use? (e.g framameet.org)"
),
":"
) ++ [443]
name =
Common.get_option(
options,
:name,
"What is the name of your instance? (e.g. Framameet)"
)
email = Common.get_option(options, :admin_email, "What is your admin email address?")
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?",
"mobilizon_prod"
)
dbuser =
Common.get_option(
options,
:dbuser,
"What is the user used to connect to your database?",
"mobilizon"
)
dbpass =
Common.get_option(
options,
:dbpass,
"What is the password used to connect to your database?",
:crypto.strong_rand_bytes(64) |> Base.url_encode64() |> binary_part(0, 64),
"autogenerated"
)
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
result_config =
EEx.eval_file(
".env.sample" |> Path.expand(__DIR__ <> "../../../../../"),
instance_domain: domain,
instance_port: port,
instance_email: email,
instance_name: name,
database_host: dbhost,
database_name: dbname,
database_port: Keyword.get(options, :dbport, 5432),
database_username: dbuser,
database_password: dbpass,
version: Mobilizon.Mixfile.project() |> Keyword.get(:version),
instance_secret: secret
)
result_psql =
EEx.eval_file(
"support/postgresql/setup_db.psql" |> Path.expand(__DIR__ <> "../../../../../"),
database_name: dbname,
database_username: dbuser,
database_password: dbpass
)
Mix.shell().info(
"Writing config to #{config_path}. You should rename it to .env.production, .env.dev or .env.test"
)
File.write(config_path, result_config)
Mix.shell().info("Writing #{psql_path}.")
File.write(psql_path, result_psql)
Mix.shell().info(
"\n" <>
"""
To get started:
1. Check the contents of the generated files.
2. Run `sudo -u postgres psql -f #{Common.escape_sh_path(psql_path)} && rm #{
Common.escape_sh_path(psql_path)
}`.
""" <>
if config_path in [".env.production", ".env.dev", ".env.test"] do
""
else
"3. Run `mv #{Common.escape_sh_path(config_path)} '.env.production'`."
end
)
else
Mix.shell().error(
"The task would have overwritten the following files:\n" <>
(Enum.map(will_overwrite, &"- #{&1}\n") |> Enum.join("")) <>
"Rerun with `-f/--force` to overwrite them."
)
end
end
end

View file

@ -0,0 +1,20 @@
defmodule Mix.Tasks.Mobilizon.Toot do
@moduledoc """
Creates a bot from a source
"""
use Mix.Task
require Logger
@shortdoc "Toot to an user"
def run([from, content]) do
Mix.Task.run("app.start")
with {:ok, _} <- MobilizonWeb.API.Comments.create_comment(from, content) do
Mix.shell().info("Tooted")
else
{:local_actor, _} -> Mix.shell().error("Failed to toot.\nActor #{from} doesn't exist")
_ -> Mix.shell().error("Failed to toot.")
end
end
end

View file

@ -1,15 +0,0 @@
defmodule Mix.Tasks.Toot do
@moduledoc """
Creates a bot from a source
"""
use Mix.Task
require Logger
@shortdoc "Toot to an user"
def run([from, content]) do
Mix.Task.run("app.start")
MobilizonWeb.API.Comments.create_comment(from, content)
end
end

View file

@ -18,7 +18,8 @@ defmodule MobilizonWeb.API.Comments do
""" """
@spec create_comment(String.t(), String.t(), String.t()) :: {:ok, Activity.t()} | any() @spec create_comment(String.t(), String.t(), String.t()) :: {:ok, Activity.t()} | any()
def create_comment(from_username, status, visibility \\ "public", inReplyToCommentURL \\ nil) do def create_comment(from_username, status, visibility \\ "public", inReplyToCommentURL \\ nil) do
with %Actor{url: url} = actor <- Actors.get_local_actor_by_name(from_username), with {:local_actor, %Actor{url: url} = actor} <-
{:local_actor, Actors.get_local_actor_by_name(from_username)},
status <- String.trim(status), status <- String.trim(status),
mentions <- Formatter.parse_mentions(status), mentions <- Formatter.parse_mentions(status),
inReplyToComment <- get_in_reply_to_comment(inReplyToCommentURL), inReplyToComment <- get_in_reply_to_comment(inReplyToCommentURL),

View file

@ -729,8 +729,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
{:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey") {:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey")
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["@context"] == assert modified["@context"] == Utils.make_json_ld_header()["@context"]
Mobilizon.Service.ActivityPub.Utils.make_json_ld_header()["@context"]
end end
test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do

View file

@ -22,12 +22,12 @@ defmodule MobilizonWeb.WebFingerTest do
test "GET /.well-known/webfinger with local actor", %{conn: conn} do test "GET /.well-known/webfinger with local actor", %{conn: conn} do
%Actor{preferred_username: username} = actor = insert(:actor) %Actor{preferred_username: username} = actor = insert(:actor)
conn = get(conn, "/.well-known/webfinger?resource=acct:#{username}@localhost:4001") conn = get(conn, "/.well-known/webfinger?resource=acct:#{username}@mobilizon.test")
assert json_response(conn, 200) == WebFinger.represent_actor(actor) assert json_response(conn, 200) == WebFinger.represent_actor(actor)
end end
test "GET /.well-known/webfinger with non existent actor", %{conn: conn} do test "GET /.well-known/webfinger with non existent actor", %{conn: conn} do
conn = get(conn, "/.well-known/webfinger?resource=acct:notme@localhost:4001") conn = get(conn, "/.well-known/webfinger?resource=acct:notme@mobilizon.test")
assert response(conn, 404) == "Couldn't find user" assert response(conn, 404) == "Couldn't find user"
end end

View file

@ -1,11 +1,10 @@
defmodule MobilizonWeb.Resolvers.CommentResolverTest do defmodule MobilizonWeb.Resolvers.CommentResolverTest do
use MobilizonWeb.ConnCase use MobilizonWeb.ConnCase
alias Mobilizon.{Events, Actors} alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, User} alias Mobilizon.Actors.{Actor, User}
alias MobilizonWeb.AbsintheHelpers alias MobilizonWeb.AbsintheHelpers
import Mobilizon.Factory
@comment %{text: "some body"} @comment %{text: "I love this event"}
setup %{conn: conn} do setup %{conn: conn} do
{:ok, %User{default_actor: %Actor{} = actor} = user} = {:ok, %User{default_actor: %Actor{} = actor} = user} =
@ -16,12 +15,10 @@ defmodule MobilizonWeb.Resolvers.CommentResolverTest do
describe "Comment Resolver" do describe "Comment Resolver" do
test "create_comment/3 creates a comment", %{conn: conn, actor: actor, user: user} do test "create_comment/3 creates a comment", %{conn: conn, actor: actor, user: user} do
category = insert(:category)
mutation = """ mutation = """
mutation { mutation {
createComment( createComment(
text: "I love this event", text: "#{@comment.text}",
actor_username: "#{actor.preferred_username}" actor_username: "#{actor.preferred_username}"
) { ) {
text, text,
@ -35,7 +32,7 @@ defmodule MobilizonWeb.Resolvers.CommentResolverTest do
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["data"]["createComment"]["text"] == "I love this event" assert json_response(res, 200)["data"]["createComment"]["text"] == @comment.text
end end
end end
end end