From bae96206d01cbf1f11815a42c1c0e5559354b1df Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Fri, 8 Mar 2019 07:47:17 +0100
Subject: priv/static/images: Add pleroma-tan
Source: https://shitposter.club/objects/9be7c3f4-5a29-45a9-ac40-301312578a02
pleroma-fox-tan-smol.png is pleroma-fox-tan.png but the width
got divided by two in The GIMP.
All the pleroma*.png got optimised with mat2 and optipng/pngcrush,
depending on their best results.
[ci skip]
---
priv/static/images/pleroma-fox-tan-smol.png | Bin 0 -> 874668 bytes
priv/static/images/pleroma-fox-tan.png | Bin 0 -> 2044257 bytes
priv/static/images/pleroma-tan.png | Bin 0 -> 545742 bytes
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 priv/static/images/pleroma-fox-tan-smol.png
create mode 100644 priv/static/images/pleroma-fox-tan.png
create mode 100644 priv/static/images/pleroma-tan.png
diff --git a/priv/static/images/pleroma-fox-tan-smol.png b/priv/static/images/pleroma-fox-tan-smol.png
new file mode 100644
index 000000000..e944d0e2a
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan-smol.png differ
diff --git a/priv/static/images/pleroma-fox-tan.png b/priv/static/images/pleroma-fox-tan.png
new file mode 100644
index 000000000..da0022ff2
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan.png differ
diff --git a/priv/static/images/pleroma-tan.png b/priv/static/images/pleroma-tan.png
new file mode 100644
index 000000000..6c12c8e46
Binary files /dev/null and b/priv/static/images/pleroma-tan.png differ
--
cgit v1.2.3
From 63ab61ed3f4988bfaf9080bcdc4fc8d5046fa57e Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 11 Mar 2019 20:37:26 +0300
Subject: Sign in via Twitter (WIP).
---
config/config.exs | 11 +++++++++++
config/dev.exs | 1 -
lib/pleroma/web/endpoint.ex | 10 ++++++----
lib/pleroma/web/oauth/oauth_controller.ex | 11 +++++++++++
lib/pleroma/web/oauth/oauth_view.ex | 1 +
lib/pleroma/web/router.ex | 12 ++++++++++++
lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 7 +++++++
mix.exs | 9 +++++++--
mix.lock | 11 ++++++++---
9 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index cd4c8e562..8c754cef3 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -369,6 +369,17 @@ config :auto_linker,
rel: false
]
+config :ueberauth,
+ Ueberauth,
+ base_path: "/oauth",
+ providers: [
+ twitter: {Ueberauth.Strategy.Twitter, []}
+ ]
+
+config :ueberauth, Ueberauth.Strategy.Twitter.OAuth,
+ consumer_key: System.get_env("TWITTER_CONSUMER_KEY"),
+ consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET")
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
diff --git a/config/dev.exs b/config/dev.exs
index f77bb9976..a7eb4b644 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -12,7 +12,6 @@ config :pleroma, Pleroma.Web.Endpoint,
protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]
],
protocol: "http",
- secure_cookie_flag: false,
debug_errors: true,
code_reloader: true,
check_origin: false,
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 3eed047ca..d906db67d 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -50,23 +50,25 @@ defmodule Pleroma.Web.Endpoint do
plug(Plug.MethodOverride)
plug(Plug.Head)
+ secure_cookies = Pleroma.Config.get([__MODULE__, :secure_cookie_flag])
+
cookie_name =
- if Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag),
+ if secure_cookies,
do: "__Host-pleroma_key",
else: "pleroma_key"
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
+ # Note: "SameSite=Strict" would cause issues with Twitter OAuth
plug(
Plug.Session,
store: :cookie,
key: cookie_name,
signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]},
http_only: true,
- secure:
- Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag),
- extra: "SameSite=Strict"
+ secure: secure_cookies,
+ extra: "SameSite=Lax"
)
plug(Pleroma.Web.Router)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 36318d69b..7b052cb36 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -15,11 +15,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
+ plug(Ueberauth)
plug(:fetch_session)
plug(:fetch_flash)
action_fallback(Pleroma.Web.OAuth.FallbackController)
+ def callback(%{assigns: %{ueberauth_failure: _failure}} = conn, _params) do
+ conn
+ |> put_flash(:error, "Failed to authenticate.")
+ |> redirect(to: "/")
+ end
+
+ def callback(%{assigns: %{ueberauth_auth: _auth}} = _conn, _params) do
+ raise "Authenticated successfully. Sign up via OAuth is not yet implemented."
+ end
+
def authorize(conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex
index 9b37a91c5..1450b5a8d 100644
--- a/lib/pleroma/web/oauth/oauth_view.ex
+++ b/lib/pleroma/web/oauth/oauth_view.ex
@@ -5,4 +5,5 @@
defmodule Pleroma.Web.OAuth.OAuthView do
use Pleroma.Web, :view
import Phoenix.HTML.Form
+ import Phoenix.HTML.Link
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 65a90e31e..7cf7794b3 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
+ pipeline :browser do
+ plug(:accepts, ["html"])
+ plug(:fetch_session)
+ end
+
pipeline :api do
plug(:accepts, ["json"])
plug(:fetch_session)
@@ -197,6 +202,13 @@ defmodule Pleroma.Web.Router do
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
+
+ scope [] do
+ pipe_through(:browser)
+
+ get("/:provider", OAuthController, :request)
+ get("/:provider/callback", OAuthController, :callback)
+ end
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index 161333847..d465f06b1 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -4,7 +4,9 @@
<%= if get_flash(@conn, :error) do %>
<%= get_flash(@conn, :error) %>
<% end %>
+
OAuth Authorization
+
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
<%= label f, :name, "Name or email" %>
@@ -33,3 +35,8 @@
<%= hidden_input f, :state, value: @state%>
<%= submit "Authorize" %>
<% end %>
+
+
+<%= link to: "/oauth/twitter", class: "alert alert-info" do %>
+ Sign in with Twitter
+<% end %>
\ No newline at end of file
diff --git a/mix.exs b/mix.exs
index 70b5e4bd6..dcd273d72 100644
--- a/mix.exs
+++ b/mix.exs
@@ -41,7 +41,7 @@ defmodule Pleroma.Mixfile do
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin],
+ extra_applications: [:logger, :runtime_tools, :comeonin, :ueberauth_twitter],
included_applications: [:ex_syslogger]
]
end
@@ -69,7 +69,8 @@ defmodule Pleroma.Mixfile do
{:phoenix_html, "~> 2.10"},
{:calendar, "~> 0.17.4"},
{:cachex, "~> 3.0.2"},
- {:httpoison, "~> 1.2.0"},
+ {:httpoison, "~> 1.2.0", override: true},
+ {:poison, "~> 3.0", override: true},
{:tesla, "~> 1.2"},
{:jason, "~> 1.0"},
{:mogrify, "~> 0.6.1"},
@@ -90,6 +91,10 @@ defmodule Pleroma.Mixfile do
{:floki, "~> 0.20.0"},
{:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"},
{:timex, "~> 3.5"},
+ {:oauth, github: "tim/erlang-oauth"},
+ # {:oauth2, "~> 0.8", override: true},
+ {:ueberauth, "~> 0.4"},
+ {:ueberauth_twitter, "~> 0.2"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}
diff --git a/mix.lock b/mix.lock
index f43a18564..92660b70a 100644
--- a/mix.lock
+++ b/mix.lock
@@ -4,7 +4,7 @@
"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"},
- "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, 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"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
@@ -26,7 +26,7 @@
"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"},
- "hackney": {:hex, :hackney, "1.14.3", "b5f6f5dcc4f1fba340762738759209e21914516df6be440d85772542d4a5e412", [:rebar3], [{:certifi, "2.4.2", [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.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "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"},
@@ -38,11 +38,14 @@
"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.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "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"},
"mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
+ "oauth": {:git, "https://github.com/tim/erlang-oauth.git", "bd19896e31125f99ff45bb5850b1c0e74b996743", []},
+ "oauth2": {:hex, :oauth2, "0.9.4", "632e8e8826a45e33ac2ea5ac66dcc019ba6bb5a0d2ba77e342d33e3b7b252c6e", [:mix], [{:hackney, "~> 1.7", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
+ "oauther": {:hex, :oauther, "1.1.1", "7d8b16167bb587ecbcddd3f8792beb9ec3e7b65c1f8ebd86b8dd25318d535752", [: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"},
@@ -63,6 +66,8 @@
"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"},
+ "ueberauth": {:hex, :ueberauth, "0.5.0", "4570ec94d7f784dc4c4aa94c83391dbd9b9bd7b66baa30e95a666c5ec1b168b1", [:mix], [{:plug, "~> 1.2", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+ "ueberauth_twitter": {:hex, :ueberauth_twitter, "0.2.4", "770ac273cc696cde986582e7a36df0923deb39fa3deff0152fbf150343809f81", [:mix], [{:httpoison, "~> 0.7", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:poison, "~> 1.3 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.2", [hex: :ueberauth, 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"},
"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"},
--
cgit v1.2.3
From d013b58e84f2c8213a5d26b1c3daf36e2f4807e5 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 12 Mar 2019 22:04:08 +0700
Subject: add `mix pleroma.user delete_activities NICKNAME` task
---
lib/mix/tasks/pleroma/user.ex | 12 ++++++++++++
lib/pleroma/user.ex | 8 ++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 037e44716..e232df14f 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -304,6 +304,18 @@ defmodule Mix.Tasks.Pleroma.User do
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} 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})
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 50e7e7ccd..2d0a8cde4 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1083,6 +1083,12 @@ defmodule Pleroma.User do
friends
|> Enum.each(fn followed -> User.unfollow(user, followed) end)
+ delete_user_activities(user)
+
+ {:ok, user}
+ end
+
+ def delete_user_activities(user) do
query = from(a in Activity, where: a.actor == ^user.ap_id)
Repo.all(query)
@@ -1096,8 +1102,6 @@ defmodule Pleroma.User do
"Doing nothing"
end
end)
-
- {:ok, user}
end
def html_filter_policy(%User{info: %{no_rich_text: true}}) do
--
cgit v1.2.3
From 16e598ec11cb9178b9fc53a1ec4b649d97c5f3b8 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 12 Mar 2019 22:12:05 +0700
Subject: fix wording
---
lib/mix/tasks/pleroma/user.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index e232df14f..ec06d908a 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -309,7 +309,7 @@ defmodule Mix.Tasks.Pleroma.User do
with %User{local: true} = user <- User.get_by_nickname(nickname) do
User.delete_user_activities(user)
- Mix.shell().info("User #{nickname} deleted.")
+ Mix.shell().info("User #{nickname} statuses deleted..")
else
_ ->
Mix.shell().error("No local user #{nickname}")
--
cgit v1.2.3
From aacbf0f57053786533df045125dee93ace0daa93 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Fri, 15 Mar 2019 17:08:03 +0300
Subject: [#923] OAuth: prototype of sign in / sign up with Twitter.
---
config/config.exs | 6 +-
lib/pleroma/user.ex | 46 ++++++++++--
lib/pleroma/web/auth/authenticator.ex | 9 ++-
lib/pleroma/web/auth/pleroma_authenticator.ex | 56 ++++++++++++++-
lib/pleroma/web/endpoint.ex | 11 ++-
lib/pleroma/web/oauth/oauth_controller.ex | 83 ++++++++++++++++------
lib/pleroma/web/oauth/oauth_view.ex | 1 -
.../web/templates/o_auth/o_auth/consumer.html.eex | 14 ++++
.../web/templates/o_auth/o_auth/show.html.eex | 8 +--
...uth_provider_and_auth_provider_uid_to_users.exs | 12 ++++
10 files changed, 209 insertions(+), 37 deletions(-)
create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
create mode 100644 priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
diff --git a/config/config.exs b/config/config.exs
index 8c754cef3..1ddc1bad1 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -369,11 +369,15 @@ config :auto_linker,
rel: false
]
+config :pleroma, :auth, oauth_consumer_enabled: false
+
config :ueberauth,
Ueberauth,
base_path: "/oauth",
providers: [
- twitter: {Ueberauth.Strategy.Twitter, []}
+ twitter:
+ {Ueberauth.Strategy.Twitter,
+ [callback_params: ~w[client_id redirect_uri scope scopes]]}
]
config :ueberauth, Ueberauth.Strategy.Twitter.OAuth,
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index f49ede149..e17df8e34 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -40,6 +40,8 @@ defmodule Pleroma.User do
field(:email, :string)
field(:name, :string)
field(:nickname, :string)
+ field(:auth_provider, :string)
+ field(:auth_provider_uid, :string)
field(:password_hash, :string)
field(:password, :string, virtual: true)
field(:password_confirmation, :string, virtual: true)
@@ -206,6 +208,36 @@ defmodule Pleroma.User do
update_and_set_cache(password_update_changeset(user, data))
end
+ # TODO: FIXME (WIP):
+ def oauth_register_changeset(struct, params \\ %{}) do
+ info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed)
+
+ changeset =
+ struct
+ |> cast(params, [:email, :nickname, :name, :bio, :auth_provider, :auth_provider_uid])
+ |> validate_required([:auth_provider, :auth_provider_uid])
+ |> unique_constraint(:email)
+ |> unique_constraint(:nickname)
+ |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames]))
+ |> validate_format(:email, @email_regex)
+ |> validate_length(:bio, max: 1000)
+ |> put_change(:info, info_change)
+
+ if changeset.valid? do
+ nickname = changeset.changes[:nickname]
+ ap_id = (nickname && User.ap_id(%User{nickname: nickname})) || nil
+ followers = User.ap_followers(%User{nickname: ap_id})
+
+ changeset
+ |> put_change(:ap_id, ap_id)
+ |> unique_constraint(:ap_id)
+ |> put_change(:following, [followers])
+ |> put_change(:follower_address, followers)
+ else
+ changeset
+ end
+ end
+
def register_changeset(struct, params \\ %{}, opts \\ []) do
confirmation_status =
if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do
@@ -504,13 +536,19 @@ defmodule Pleroma.User do
end
end
+ def get_by_email(email), do: Repo.get_by(User, email: email)
+
def get_by_nickname_or_email(nickname_or_email) do
- case user = Repo.get_by(User, nickname: nickname_or_email) do
- %User{} -> user
- nil -> Repo.get_by(User, email: nickname_or_email)
- end
+ get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
end
+ def get_by_auth_provider_uid(auth_provider, auth_provider_uid),
+ do:
+ Repo.get_by(User,
+ auth_provider: to_string(auth_provider),
+ auth_provider_uid: to_string(auth_provider_uid)
+ )
+
def get_cached_user_info(user) do
key = "user_info:#{user.id}"
Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end)
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index 82267c595..fa439d562 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -12,8 +12,13 @@ defmodule Pleroma.Web.Auth.Authenticator do
)
end
- @callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
- def get_user(plug), do: implementation().get_user(plug)
+ @callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()}
+ def get_user(plug, params), do: implementation().get_user(plug, params)
+
+ @callback get_or_create_user_by_oauth(Plug.Conn.t(), Map.t()) ::
+ {:ok, User.t()} | {:error, any()}
+ def get_or_create_user_by_oauth(plug, params),
+ do: implementation().get_or_create_user_by_oauth(plug, params)
@callback handle_error(Plug.Conn.t(), any()) :: any()
def handle_error(plug, error), do: implementation().handle_error(plug, error)
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 3cc19af01..fb04ef8da 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -8,9 +8,9 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
@behaviour Pleroma.Web.Auth.Authenticator
- def get_user(%Plug.Conn{} = conn) do
- %{"authorization" => %{"name" => name, "password" => password}} = conn.params
-
+ def get_user(%Plug.Conn{} = _conn, %{
+ "authorization" => %{"name" => name, "password" => password}
+ }) do
with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
{:ok, user}
@@ -20,6 +20,56 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
end
end
+ def get_user(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials}
+
+ def get_or_create_user_by_oauth(
+ %Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}},
+ _params
+ ) do
+ user = User.get_by_auth_provider_uid(provider, uid)
+
+ if user do
+ {:ok, user}
+ else
+ info = auth.info
+ email = info.email
+ nickname = info.nickname
+
+ # TODO: FIXME: connect to existing (non-oauth) account (need a UI flow for that) / generate a random nickname?
+ email =
+ if email && User.get_by_email(email) do
+ nil
+ else
+ email
+ end
+
+ nickname =
+ if nickname && User.get_by_nickname(nickname) do
+ nil
+ else
+ nickname
+ end
+
+ new_user =
+ User.oauth_register_changeset(
+ %User{},
+ %{
+ auth_provider: to_string(provider),
+ auth_provider_uid: to_string(uid),
+ name: info.name,
+ bio: info.description,
+ email: email,
+ nickname: nickname
+ }
+ )
+
+ Pleroma.Repo.insert(new_user)
+ end
+ end
+
+ def get_or_create_user_by_oauth(%Plug.Conn{} = _conn, _params),
+ do: {:error, :missing_credentials}
+
def handle_error(%Plug.Conn{} = _conn, error) do
error
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index d906db67d..31ffdecc0 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -57,10 +57,17 @@ defmodule Pleroma.Web.Endpoint do
do: "__Host-pleroma_key",
else: "pleroma_key"
+ same_site =
+ if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do
+ # Note: "SameSite=Strict" prevents sign in with external OAuth provider (no cookies during callback request)
+ "SameSite=Lax"
+ else
+ "SameSite=Strict"
+ end
+
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
- # Note: "SameSite=Strict" would cause issues with Twitter OAuth
plug(
Plug.Session,
store: :cookie,
@@ -68,7 +75,7 @@ defmodule Pleroma.Web.Endpoint do
signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]},
http_only: true,
secure: secure_cookies,
- extra: "SameSite=Lax"
+ extra: same_site
)
plug(Pleroma.Web.Router)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 7b052cb36..366085a57 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -15,20 +15,57 @@ defmodule Pleroma.Web.OAuth.OAuthController do
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
- plug(Ueberauth)
+ if Pleroma.Config.get([:auth, :oauth_consumer_enabled]), do: plug(Ueberauth)
+
plug(:fetch_session)
plug(:fetch_flash)
action_fallback(Pleroma.Web.OAuth.FallbackController)
- def callback(%{assigns: %{ueberauth_failure: _failure}} = conn, _params) do
+ def request(conn, params) do
+ message =
+ if params["provider"] do
+ "Unsupported OAuth provider: #{params["provider"]}."
+ else
+ "Bad OAuth request."
+ end
+
conn
- |> put_flash(:error, "Failed to authenticate.")
+ |> put_flash(:error, message)
|> redirect(to: "/")
end
- def callback(%{assigns: %{ueberauth_auth: _auth}} = _conn, _params) do
- raise "Authenticated successfully. Sign up via OAuth is not yet implemented."
+ def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do
+ messages = for e <- Map.get(failure, :errors, []), do: e.message
+ message = Enum.join(messages, "; ")
+
+ conn
+ |> put_flash(:error, "Failed to authenticate: #{message}.")
+ |> redirect(external: redirect_uri(conn, redirect_uri))
+ end
+
+ def callback(
+ conn,
+ %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params
+ ) do
+ with {:ok, user} <- Authenticator.get_or_create_user_by_oauth(conn, params) do
+ do_create_authorization(
+ conn,
+ %{
+ "authorization" => %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri,
+ "scope" => oauth_scopes(params, nil)
+ }
+ },
+ user
+ )
+ else
+ _ ->
+ conn
+ |> put_flash(:error, "Failed to set up user account.")
+ |> redirect(external: redirect_uri(conn, redirect_uri))
+ end
end
def authorize(conn, params) do
@@ -47,14 +84,21 @@ defmodule Pleroma.Web.OAuth.OAuthController do
})
end
- def create_authorization(conn, %{
- "authorization" =>
- %{
- "client_id" => client_id,
- "redirect_uri" => redirect_uri
- } = auth_params
- }) do
- with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)},
+ def create_authorization(conn, params), do: do_create_authorization(conn, params, nil)
+
+ defp do_create_authorization(
+ conn,
+ %{
+ "authorization" =>
+ %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri
+ } = auth_params
+ } = params,
+ user
+ ) do
+ with {_, {:ok, %User{} = user}} <-
+ {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
scopes <- oauth_scopes(auth_params, []),
@@ -63,13 +107,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
- redirect_uri =
- if redirect_uri == "." do
- # Special case: Local MastodonFE
- mastodon_api_url(conn, :login)
- else
- redirect_uri
- end
+ redirect_uri = redirect_uri(conn, redirect_uri)
cond do
redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
@@ -225,4 +263,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
nil
end
end
+
+ # Special case: Local MastodonFE
+ defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
+
+ defp redirect_uri(_conn, redirect_uri), do: redirect_uri
end
diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex
index 1450b5a8d..9b37a91c5 100644
--- a/lib/pleroma/web/oauth/oauth_view.ex
+++ b/lib/pleroma/web/oauth/oauth_view.ex
@@ -5,5 +5,4 @@
defmodule Pleroma.Web.OAuth.OAuthView do
use Pleroma.Web, :view
import Phoenix.HTML.Form
- import Phoenix.HTML.Link
end
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
new file mode 100644
index 000000000..e7251bce8
--- /dev/null
+++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
@@ -0,0 +1,14 @@
+External OAuth Authorization
+<%= form_for @conn, o_auth_path(@conn, :request, :twitter), [method: "get"], fn f -> %>
+
+
+ <%= hidden_input f, :client_id, value: @client_id %>
+ <%= hidden_input f, :redirect_uri, value: @redirect_uri %>
+ <%= hidden_input f, :state, value: @state%>
+ <%= submit "Sign in with Twitter" %>
+<% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index d465f06b1..2fa7837fc 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -36,7 +36,7 @@
<%= submit "Authorize" %>
<% end %>
-
-<%= link to: "/oauth/twitter", class: "alert alert-info" do %>
- Sign in with Twitter
-<% end %>
\ No newline at end of file
+<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %>
+
+ <%= render @view_module, "consumer.html", assigns %>
+<% end %>
diff --git a/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs b/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
new file mode 100644
index 000000000..90947f85a
--- /dev/null
+++ b/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
@@ -0,0 +1,12 @@
+defmodule Pleroma.Repo.Migrations.AddAuthProviderAndAuthProviderUidToUsers do
+ use Ecto.Migration
+
+ def change do
+ alter table(:users) do
+ add :auth_provider, :string
+ add :auth_provider_uid, :string
+ end
+
+ create unique_index(:users, [:auth_provider, :auth_provider_uid])
+ end
+end
--
cgit v1.2.3
From 26b63540953f6a65bb52531b434fd6ab85aaedfe Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 18 Mar 2019 17:23:38 +0300
Subject: [#923] Support for multiple (external) registrations per user via
Registration.
---
config/config.exs | 2 +-
lib/pleroma/registration.ex | 36 +++++++++++++++
lib/pleroma/user.ex | 16 ++-----
lib/pleroma/web/auth/authenticator.ex | 6 +--
lib/pleroma/web/auth/ldap_authenticator.ex | 2 +-
lib/pleroma/web/auth/pleroma_authenticator.ex | 51 +++++++++++++---------
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
...uth_provider_and_auth_provider_uid_to_users.exs | 12 -----
.../20190315101315_create_registrations.exs | 16 +++++++
9 files changed, 93 insertions(+), 50 deletions(-)
create mode 100644 lib/pleroma/registration.ex
delete mode 100644 priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
create mode 100644 priv/repo/migrations/20190315101315_create_registrations.exs
diff --git a/config/config.exs b/config/config.exs
index 6839b489b..03baf894d 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -381,7 +381,7 @@ config :pleroma, :ldap,
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
uid: System.get_env("LDAP_UID") || "cn"
-config :pleroma, :auth, oauth_consumer_enabled: false
+config :pleroma, :auth, oauth_consumer_enabled: System.get_env("OAUTH_CONSUMER_ENABLED") == "true"
config :ueberauth,
Ueberauth,
diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex
new file mode 100644
index 000000000..1bd91a316
--- /dev/null
+++ b/lib/pleroma/registration.ex
@@ -0,0 +1,36 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Registration do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+
+ alias Pleroma.Registration
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ schema "registrations" do
+ belongs_to(:user, User, type: Pleroma.FlakeId)
+ field(:provider, :string)
+ field(:uid, :string)
+ field(:info, :map, default: %{})
+
+ timestamps()
+ end
+
+ def changeset(registration, params \\ %{}) do
+ registration
+ |> cast(params, [:user_id, :provider, :uid, :info])
+ |> foreign_key_constraint(:user_id)
+ |> unique_constraint(:uid, name: :registrations_provider_uid_index)
+ end
+
+ def get_by_provider_uid(provider, uid) do
+ Repo.get_by(Registration,
+ provider: to_string(provider),
+ uid: to_string(uid)
+ )
+ end
+end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 7f8b282e0..bd742b2fd 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.User do
alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object
+ alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
@@ -41,8 +42,6 @@ defmodule Pleroma.User do
field(:email, :string)
field(:name, :string)
field(:nickname, :string)
- field(:auth_provider, :string)
- field(:auth_provider_uid, :string)
field(:password_hash, :string)
field(:password, :string, virtual: true)
field(:password_confirmation, :string, virtual: true)
@@ -56,6 +55,7 @@ defmodule Pleroma.User do
field(:bookmarks, {:array, :string}, default: [])
field(:last_refreshed_at, :naive_datetime)
has_many(:notifications, Notification)
+ has_many(:registrations, Registration)
embeds_one(:info, Pleroma.User.Info)
timestamps()
@@ -210,13 +210,12 @@ defmodule Pleroma.User do
end
# TODO: FIXME (WIP):
- def oauth_register_changeset(struct, params \\ %{}) do
+ def external_registration_changeset(struct, params \\ %{}) do
info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed)
changeset =
struct
- |> cast(params, [:email, :nickname, :name, :bio, :auth_provider, :auth_provider_uid])
- |> validate_required([:auth_provider, :auth_provider_uid])
+ |> cast(params, [:email, :nickname, :name, :bio])
|> unique_constraint(:email)
|> unique_constraint(:nickname)
|> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames]))
@@ -544,13 +543,6 @@ defmodule Pleroma.User do
get_by_nickname(nickname_or_email) || get_by_email(nickname_or_email)
end
- def get_by_auth_provider_uid(auth_provider, auth_provider_uid),
- do:
- Repo.get_by(User,
- auth_provider: to_string(auth_provider),
- auth_provider_uid: to_string(auth_provider_uid)
- )
-
def get_cached_user_info(user) do
key = "user_info:#{user.id}"
Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end)
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index fa439d562..11f45eec3 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -15,10 +15,10 @@ defmodule Pleroma.Web.Auth.Authenticator do
@callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()}
def get_user(plug, params), do: implementation().get_user(plug, params)
- @callback get_or_create_user_by_oauth(Plug.Conn.t(), Map.t()) ::
+ @callback get_by_external_registration(Plug.Conn.t(), Map.t()) ::
{:ok, User.t()} | {:error, any()}
- def get_or_create_user_by_oauth(plug, params),
- do: implementation().get_or_create_user_by_oauth(plug, params)
+ def get_by_external_registration(plug, params),
+ do: implementation().get_by_external_registration(plug, params)
@callback handle_error(Plug.Conn.t(), any()) :: any()
def handle_error(plug, error), do: implementation().handle_error(plug, error)
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 6c65cff27..51a0f0fa2 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -40,7 +40,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
end
end
- def get_or_create_user_by_oauth(conn, params), do: get_user(conn, params)
+ def get_by_external_registration(conn, params), do: get_user(conn, params)
def handle_error(%Plug.Conn{} = _conn, error) do
error
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 2e2bcfb70..2d4399490 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -5,6 +5,8 @@
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Comeonin.Pbkdf2
alias Pleroma.User
+ alias Pleroma.Registration
+ alias Pleroma.Repo
@behaviour Pleroma.Web.Auth.Authenticator
@@ -27,20 +29,21 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
end
end
- def get_or_create_user_by_oauth(
+ def get_by_external_registration(
%Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}},
_params
) do
- user = User.get_by_auth_provider_uid(provider, uid)
+ registration = Registration.get_by_provider_uid(provider, uid)
- if user do
+ if registration do
+ user = Repo.preload(registration, :user).user
{:ok, user}
else
info = auth.info
email = info.email
nickname = info.nickname
- # TODO: FIXME: connect to existing (non-oauth) account (need a UI flow for that) / generate a random nickname?
+ # Note: nullifying email in case this email is already taken
email =
if email && User.get_by_email(email) do
nil
@@ -48,31 +51,39 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
email
end
+ # Note: generating a random numeric suffix to nickname in case this nickname is already taken
nickname =
if nickname && User.get_by_nickname(nickname) do
- nil
+ "#{nickname}_#{:os.system_time()}"
else
nickname
end
- new_user =
- User.oauth_register_changeset(
- %User{},
- %{
- auth_provider: to_string(provider),
- auth_provider_uid: to_string(uid),
- name: info.name,
- bio: info.description,
- email: email,
- nickname: nickname
- }
- )
-
- Pleroma.Repo.insert(new_user)
+ with {:ok, new_user} <-
+ User.external_registration_changeset(
+ %User{},
+ %{
+ name: info.name,
+ bio: info.description,
+ email: email,
+ nickname: nickname
+ }
+ )
+ |> Repo.insert(),
+ {:ok, _} <-
+ Registration.changeset(%Registration{}, %{
+ user_id: new_user.id,
+ provider: to_string(provider),
+ uid: to_string(uid),
+ info: %{nickname: info.nickname, email: info.email}
+ })
+ |> Repo.insert() do
+ {:ok, new_user}
+ end
end
end
- def get_or_create_user_by_oauth(%Plug.Conn{} = _conn, _params),
+ def get_by_external_registration(%Plug.Conn{} = _conn, _params),
do: {:error, :missing_credentials}
def handle_error(%Plug.Conn{} = _conn, error) do
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 588933d31..8c864cb1d 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
conn,
%{"client_id" => client_id, "redirect_uri" => redirect_uri} = params
) do
- with {:ok, user} <- Authenticator.get_or_create_user_by_oauth(conn, params) do
+ with {:ok, user} <- Authenticator.get_by_external_registration(conn, params) do
do_create_authorization(
conn,
%{
diff --git a/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs b/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
deleted file mode 100644
index 90947f85a..000000000
--- a/priv/repo/migrations/20190315101315_add_auth_provider_and_auth_provider_uid_to_users.exs
+++ /dev/null
@@ -1,12 +0,0 @@
-defmodule Pleroma.Repo.Migrations.AddAuthProviderAndAuthProviderUidToUsers do
- use Ecto.Migration
-
- def change do
- alter table(:users) do
- add :auth_provider, :string
- add :auth_provider_uid, :string
- end
-
- create unique_index(:users, [:auth_provider, :auth_provider_uid])
- end
-end
diff --git a/priv/repo/migrations/20190315101315_create_registrations.exs b/priv/repo/migrations/20190315101315_create_registrations.exs
new file mode 100644
index 000000000..dac86b780
--- /dev/null
+++ b/priv/repo/migrations/20190315101315_create_registrations.exs
@@ -0,0 +1,16 @@
+defmodule Pleroma.Repo.Migrations.CreateRegistrations do
+ use Ecto.Migration
+
+ def change do
+ create table(:registrations) do
+ add :user_id, references(:users, type: :uuid, on_delete: :delete_all)
+ add :provider, :string
+ add :uid, :string
+ add :info, :map, default: %{}
+
+ timestamps()
+ end
+
+ create unique_index(:registrations, [:provider, :uid])
+ end
+end
--
cgit v1.2.3
From 8d21859717a75e01128f50b0b51efdd0a4748670 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 18 Mar 2019 18:09:53 +0300
Subject: [#923] External User registration refactoring, password
randomization.
---
lib/pleroma/user.ex | 38 ++++++---------------------
lib/pleroma/web/auth/pleroma_authenticator.ex | 14 +++++++---
2 files changed, 18 insertions(+), 34 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index bd742b2fd..558216894 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -209,35 +209,6 @@ defmodule Pleroma.User do
update_and_set_cache(password_update_changeset(user, data))
end
- # TODO: FIXME (WIP):
- def external_registration_changeset(struct, params \\ %{}) do
- info_change = User.Info.confirmation_changeset(%User.Info{}, :confirmed)
-
- changeset =
- struct
- |> cast(params, [:email, :nickname, :name, :bio])
- |> unique_constraint(:email)
- |> unique_constraint(:nickname)
- |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames]))
- |> validate_format(:email, @email_regex)
- |> validate_length(:bio, max: 1000)
- |> put_change(:info, info_change)
-
- if changeset.valid? do
- nickname = changeset.changes[:nickname]
- ap_id = (nickname && User.ap_id(%User{nickname: nickname})) || nil
- followers = User.ap_followers(%User{nickname: ap_id})
-
- changeset
- |> put_change(:ap_id, ap_id)
- |> unique_constraint(:ap_id)
- |> put_change(:following, [followers])
- |> put_change(:follower_address, followers)
- else
- changeset
- end
- end
-
def register_changeset(struct, params \\ %{}, opts \\ []) do
confirmation_status =
if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do
@@ -251,7 +222,7 @@ defmodule Pleroma.User do
changeset =
struct
|> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation])
- |> validate_required([:email, :name, :nickname, :password, :password_confirmation])
+ |> validate_required([:name, :nickname, :password, :password_confirmation])
|> validate_confirmation(:password)
|> unique_constraint(:email)
|> unique_constraint(:nickname)
@@ -262,6 +233,13 @@ defmodule Pleroma.User do
|> validate_length(:name, min: 1, max: 100)
|> put_change(:info, info_change)
+ changeset =
+ if opts[:external] do
+ changeset
+ else
+ validate_required(changeset, [:email])
+ end
+
if changeset.valid? do
hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
ap_id = User.ap_id(%User{nickname: changeset.changes[:nickname]})
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 2d4399490..36ecd0560 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -54,20 +54,26 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
# Note: generating a random numeric suffix to nickname in case this nickname is already taken
nickname =
if nickname && User.get_by_nickname(nickname) do
- "#{nickname}_#{:os.system_time()}"
+ "#{nickname}#{:os.system_time()}"
else
nickname
end
+ random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
+
with {:ok, new_user} <-
- User.external_registration_changeset(
+ User.register_changeset(
%User{},
%{
name: info.name,
bio: info.description,
email: email,
- nickname: nickname
- }
+ nickname: nickname,
+ password: random_password,
+ password_confirmation: random_password
+ },
+ external: true,
+ confirmed: true
)
|> Repo.insert(),
{:ok, _} <-
--
cgit v1.2.3
From 40e9a04c31a9965dee92cb8f07ed6db28f8ccd75 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 18 Mar 2019 20:31:24 +0300
Subject: [#923] Registration validations & unique index on [:user_id,
:provider].
---
lib/pleroma/registration.ex | 1 +
priv/repo/migrations/20190315101315_create_registrations.exs | 1 +
2 files changed, 2 insertions(+)
diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex
index 1bd91a316..773e25fa6 100644
--- a/lib/pleroma/registration.ex
+++ b/lib/pleroma/registration.ex
@@ -23,6 +23,7 @@ defmodule Pleroma.Registration do
def changeset(registration, params \\ %{}) do
registration
|> cast(params, [:user_id, :provider, :uid, :info])
+ |> validate_required([:provider, :uid])
|> foreign_key_constraint(:user_id)
|> unique_constraint(:uid, name: :registrations_provider_uid_index)
end
diff --git a/priv/repo/migrations/20190315101315_create_registrations.exs b/priv/repo/migrations/20190315101315_create_registrations.exs
index dac86b780..c566912f5 100644
--- a/priv/repo/migrations/20190315101315_create_registrations.exs
+++ b/priv/repo/migrations/20190315101315_create_registrations.exs
@@ -12,5 +12,6 @@ defmodule Pleroma.Repo.Migrations.CreateRegistrations do
end
create unique_index(:registrations, [:provider, :uid])
+ create unique_index(:registrations, [:user_id, :provider])
end
end
--
cgit v1.2.3
From e17a9a1f6680bfc464a1433fcff37b6d61cc5340 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Wed, 20 Mar 2019 10:35:31 +0300
Subject: [#923] Nickname & email selection for external registrations, option
to connect to existing account.
---
lib/pleroma/registration.ex | 20 ++
lib/pleroma/web/auth/authenticator.ex | 12 +-
lib/pleroma/web/auth/ldap_authenticator.ex | 11 +-
lib/pleroma/web/auth/pleroma_authenticator.ex | 89 ++++----
lib/pleroma/web/oauth/oauth_controller.ex | 245 +++++++++++++++------
lib/pleroma/web/router.ex | 2 +
.../web/templates/o_auth/o_auth/register.html.eex | 48 ++++
.../20190315101315_create_registrations.exs | 3 +-
8 files changed, 306 insertions(+), 124 deletions(-)
create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex
index 773e25fa6..21fd1fc3f 100644
--- a/lib/pleroma/registration.ex
+++ b/lib/pleroma/registration.ex
@@ -11,6 +11,8 @@ defmodule Pleroma.Registration do
alias Pleroma.Repo
alias Pleroma.User
+ @primary_key {:id, Pleroma.FlakeId, autogenerate: true}
+
schema "registrations" do
belongs_to(:user, User, type: Pleroma.FlakeId)
field(:provider, :string)
@@ -20,6 +22,18 @@ defmodule Pleroma.Registration do
timestamps()
end
+ def nickname(registration, default \\ nil),
+ do: Map.get(registration.info, "nickname", default)
+
+ def email(registration, default \\ nil),
+ do: Map.get(registration.info, "email", default)
+
+ def name(registration, default \\ nil),
+ do: Map.get(registration.info, "name", default)
+
+ def description(registration, default \\ nil),
+ do: Map.get(registration.info, "description", default)
+
def changeset(registration, params \\ %{}) do
registration
|> cast(params, [:user_id, :provider, :uid, :info])
@@ -28,6 +42,12 @@ defmodule Pleroma.Registration do
|> unique_constraint(:uid, name: :registrations_provider_uid_index)
end
+ def bind_to_user(registration, user) do
+ registration
+ |> changeset(%{user_id: (user && user.id) || nil})
+ |> Repo.update()
+ end
+
def get_by_provider_uid(provider, uid) do
Repo.get_by(Registration,
provider: to_string(provider),
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index 11f45eec3..1f614668c 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.Auth.Authenticator do
alias Pleroma.User
+ alias Pleroma.Registration
def implementation do
Pleroma.Config.get(
@@ -15,10 +16,15 @@ defmodule Pleroma.Web.Auth.Authenticator do
@callback get_user(Plug.Conn.t(), Map.t()) :: {:ok, User.t()} | {:error, any()}
def get_user(plug, params), do: implementation().get_user(plug, params)
- @callback get_by_external_registration(Plug.Conn.t(), Map.t()) ::
+ @callback create_from_registration(Plug.Conn.t(), Map.t(), Registration.t()) ::
{:ok, User.t()} | {:error, any()}
- def get_by_external_registration(plug, params),
- do: implementation().get_by_external_registration(plug, params)
+ def create_from_registration(plug, params, registration),
+ do: implementation().create_from_registration(plug, params, registration)
+
+ @callback get_registration(Plug.Conn.t(), Map.t()) ::
+ {:ok, Registration.t()} | {:error, any()}
+ def get_registration(plug, params),
+ do: implementation().get_registration(plug, params)
@callback handle_error(Plug.Conn.t(), any()) :: any()
def handle_error(plug, error), do: implementation().handle_error(plug, error)
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 51a0f0fa2..65abd7f38 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -8,10 +8,15 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
require Logger
@behaviour Pleroma.Web.Auth.Authenticator
+ @base Pleroma.Web.Auth.PleromaAuthenticator
@connection_timeout 10_000
@search_timeout 10_000
+ defdelegate get_registration(conn, params), to: @base
+
+ defdelegate create_from_registration(conn, params, registration), to: @base
+
def get_user(%Plug.Conn{} = conn, params) do
if Pleroma.Config.get([:ldap, :enabled]) do
{name, password} =
@@ -29,19 +34,17 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
{:error, {:ldap_connection_error, _}} ->
# When LDAP is unavailable, try default authenticator
- Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn, params)
+ @base.get_user(conn, params)
error ->
error
end
else
# Fall back to default authenticator
- Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn, params)
+ @base.get_user(conn, params)
end
end
- def get_by_external_registration(conn, params), do: get_user(conn, params)
-
def handle_error(%Plug.Conn{} = _conn, error) do
error
end
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 36ecd0560..60847ce6a 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -29,68 +29,63 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
end
end
- def get_by_external_registration(
+ def get_registration(
%Plug.Conn{assigns: %{ueberauth_auth: %{provider: provider, uid: uid} = auth}},
_params
) do
registration = Registration.get_by_provider_uid(provider, uid)
if registration do
- user = Repo.preload(registration, :user).user
- {:ok, user}
+ {:ok, registration}
else
info = auth.info
- email = info.email
- nickname = info.nickname
- # Note: nullifying email in case this email is already taken
- email =
- if email && User.get_by_email(email) do
- nil
- else
- email
- end
+ Registration.changeset(%Registration{}, %{
+ provider: to_string(provider),
+ uid: to_string(uid),
+ info: %{
+ "nickname" => info.nickname,
+ "email" => info.email,
+ "name" => info.name,
+ "description" => info.description
+ }
+ })
+ |> Repo.insert()
+ end
+ end
- # Note: generating a random numeric suffix to nickname in case this nickname is already taken
- nickname =
- if nickname && User.get_by_nickname(nickname) do
- "#{nickname}#{:os.system_time()}"
- else
- nickname
- end
+ def get_registration(%Plug.Conn{} = _conn, _params), do: {:error, :missing_credentials}
- random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
+ def create_from_registration(_conn, params, registration) do
+ nickname = value([params["nickname"], Registration.nickname(registration)])
+ email = value([params["email"], Registration.email(registration)])
+ name = value([params["name"], Registration.name(registration)]) || nickname
+ bio = value([params["bio"], Registration.description(registration)])
- with {:ok, new_user} <-
- User.register_changeset(
- %User{},
- %{
- name: info.name,
- bio: info.description,
- email: email,
- nickname: nickname,
- password: random_password,
- password_confirmation: random_password
- },
- external: true,
- confirmed: true
- )
- |> Repo.insert(),
- {:ok, _} <-
- Registration.changeset(%Registration{}, %{
- user_id: new_user.id,
- provider: to_string(provider),
- uid: to_string(uid),
- info: %{nickname: info.nickname, email: info.email}
- })
- |> Repo.insert() do
- {:ok, new_user}
- end
+ random_password = :crypto.strong_rand_bytes(64) |> Base.encode64()
+
+ with {:ok, new_user} <-
+ User.register_changeset(
+ %User{},
+ %{
+ email: email,
+ nickname: nickname,
+ name: name,
+ bio: bio,
+ password: random_password,
+ password_confirmation: random_password
+ },
+ external: true,
+ confirmed: true
+ )
+ |> Repo.insert(),
+ {:ok, _} <-
+ Registration.changeset(registration, %{user_id: new_user.id}) |> Repo.update() do
+ {:ok, new_user}
end
end
- def get_by_external_registration(%Plug.Conn{} = _conn, _params),
- do: {:error, :missing_credentials}
+ defp value(list), do: Enum.find(list, &(to_string(&1) != ""))
def handle_error(%Plug.Conn{} = _conn, error) do
error
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 8c864cb1d..a2c62ae68 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.Registration
alias Pleroma.Web.Auth.Authenticator
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
@@ -21,52 +22,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do
action_fallback(Pleroma.Web.OAuth.FallbackController)
- def request(conn, params) do
- message =
- if params["provider"] do
- "Unsupported OAuth provider: #{params["provider"]}."
- else
- "Bad OAuth request."
- end
-
- conn
- |> put_flash(:error, message)
- |> redirect(to: "/")
- end
-
- def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do
- messages = for e <- Map.get(failure, :errors, []), do: e.message
- message = Enum.join(messages, "; ")
-
- conn
- |> put_flash(:error, "Failed to authenticate: #{message}.")
- |> redirect(external: redirect_uri(conn, redirect_uri))
- end
-
- def callback(
- conn,
- %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params
- ) do
- with {:ok, user} <- Authenticator.get_by_external_registration(conn, params) do
- do_create_authorization(
- conn,
- %{
- "authorization" => %{
- "client_id" => client_id,
- "redirect_uri" => redirect_uri,
- "scope" => oauth_scopes(params, nil)
- }
- },
- user
- )
- else
- _ ->
- conn
- |> put_flash(:error, "Failed to set up user account.")
- |> redirect(external: redirect_uri(conn, redirect_uri))
- end
- end
-
def authorize(conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
@@ -83,29 +38,16 @@ defmodule Pleroma.Web.OAuth.OAuthController do
})
end
- def create_authorization(conn, params), do: do_create_authorization(conn, params, nil)
-
- defp do_create_authorization(
- conn,
- %{
- "authorization" =>
- %{
- "client_id" => client_id,
- "redirect_uri" => redirect_uri
- } = auth_params
- } = params,
- user
- ) do
- with {_, {:ok, %User{} = user}} <-
- {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)},
- %App{} = app <- Repo.get_by(App, client_id: client_id),
- true <- redirect_uri in String.split(app.redirect_uris),
- scopes <- oauth_scopes(auth_params, []),
- {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes},
- # Note: `scope` param is intentionally not optional in this context
- {:missing_scopes, false} <- {:missing_scopes, scopes == []},
- {:auth_active, true} <- {:auth_active, User.auth_active?(user)},
- {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
+ def create_authorization(
+ conn,
+ %{
+ "authorization" => %{"redirect_uri" => redirect_uri} = auth_params
+ } = params,
+ opts \\ []
+ ) do
+ with {:ok, auth} <-
+ (opts[:auth] && {:ok, opts[:auth]}) ||
+ do_create_authorization(conn, params, opts[:user]) do
redirect_uri = redirect_uri(conn, redirect_uri)
cond do
@@ -232,6 +174,166 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
+ def request(conn, params) do
+ message =
+ if params["provider"] do
+ "Unsupported OAuth provider: #{params["provider"]}."
+ else
+ "Bad OAuth request."
+ end
+
+ conn
+ |> put_flash(:error, message)
+ |> redirect(to: "/")
+ end
+
+ def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do
+ messages = for e <- Map.get(failure, :errors, []), do: e.message
+ message = Enum.join(messages, "; ")
+
+ conn
+ |> put_flash(:error, "Failed to authenticate: #{message}.")
+ |> redirect(external: redirect_uri(conn, redirect_uri))
+ end
+
+ def callback(
+ conn,
+ %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params
+ ) do
+ with {:ok, registration} <- Authenticator.get_registration(conn, params) do
+ user = Repo.preload(registration, :user).user
+
+ auth_params = %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri,
+ "scopes" => oauth_scopes(params, nil)
+ }
+
+ if user do
+ create_authorization(
+ conn,
+ %{"authorization" => auth_params},
+ user: user
+ )
+ else
+ registration_params =
+ Map.merge(auth_params, %{
+ "nickname" => Registration.nickname(registration),
+ "email" => Registration.email(registration)
+ })
+
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> redirect(to: o_auth_path(conn, :registration_details, registration_params))
+ end
+ else
+ _ ->
+ conn
+ |> put_flash(:error, "Failed to set up user account.")
+ |> redirect(external: redirect_uri(conn, redirect_uri))
+ end
+ end
+
+ def registration_details(conn, params) do
+ render(conn, "register.html", %{
+ client_id: params["client_id"],
+ redirect_uri: params["redirect_uri"],
+ scopes: oauth_scopes(params, []),
+ nickname: params["nickname"],
+ email: params["email"]
+ })
+ end
+
+ def register(conn, %{"op" => "connect"} = params) do
+ create_authorization_params = %{
+ "authorization" => Map.merge(params, %{"name" => params["auth_name"]})
+ }
+
+ with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
+ %Registration{} = registration <- Repo.get(Registration, registration_id),
+ {:ok, auth} <- do_create_authorization(conn, create_authorization_params),
+ %User{} = user <- Repo.preload(auth, :user).user,
+ {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
+ conn
+ |> put_session_registration_id(nil)
+ |> create_authorization(
+ create_authorization_params,
+ auth: auth
+ )
+ else
+ _ ->
+ conn
+ |> put_flash(:error, "Unknown error, please try again.")
+ |> redirect(to: o_auth_path(conn, :registration_details, params))
+ end
+ end
+
+ def register(conn, params) do
+ with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
+ %Registration{} = registration <- Repo.get(Registration, registration_id),
+ {:ok, user} <- Authenticator.create_from_registration(conn, params, registration) do
+ conn
+ |> put_session_registration_id(nil)
+ |> create_authorization(
+ %{
+ "authorization" => %{
+ "client_id" => params["client_id"],
+ "redirect_uri" => params["redirect_uri"],
+ "scopes" => oauth_scopes(params, nil)
+ }
+ },
+ user: user
+ )
+ else
+ {:error, changeset} ->
+ message =
+ Enum.map(changeset.errors, fn {field, {error, _}} ->
+ "#{field} #{error}"
+ end)
+ |> Enum.join("; ")
+
+ message =
+ String.replace(
+ message,
+ "ap_id has already been taken",
+ "nickname has already been taken"
+ )
+
+ conn
+ |> put_flash(:error, "Error: #{message}.")
+ |> redirect(to: o_auth_path(conn, :registration_details, params))
+
+ _ ->
+ conn
+ |> put_flash(:error, "Unknown error, please try again.")
+ |> redirect(to: o_auth_path(conn, :registration_details, params))
+ end
+ end
+
+ defp do_create_authorization(
+ conn,
+ %{
+ "authorization" =>
+ %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri
+ } = auth_params
+ } = params,
+ user \\ nil
+ ) do
+ with {_, {:ok, %User{} = user}} <-
+ {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn, params)},
+ %App{} = app <- Repo.get_by(App, client_id: client_id),
+ true <- redirect_uri in String.split(app.redirect_uris),
+ scopes <- oauth_scopes(auth_params, []),
+ {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes},
+ # Note: `scope` param is intentionally not optional in this context
+ {:missing_scopes, false} <- {:missing_scopes, scopes == []},
+ {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
+ Authorization.create_authorization(app, user, scopes)
+ end
+ end
+
# XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be
# decoding it. Investigate sometime.
defp fix_padding(token) do
@@ -269,4 +371,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
defp redirect_uri(_conn, redirect_uri), do: redirect_uri
+
+ defp get_session_registration_id(conn), do: get_session(conn, :registration_id)
+
+ defp put_session_registration_id(conn, registration_id),
+ do: put_session(conn, :registration_id, registration_id)
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 9b6784120..f2cec574b 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -208,12 +208,14 @@ defmodule Pleroma.Web.Router do
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
+ get("/registration_details", OAuthController, :registration_details)
scope [] do
pipe_through(:browser)
get("/:provider", OAuthController, :request)
get("/:provider/callback", OAuthController, :callback)
+ post("/register", OAuthController, :register)
end
end
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
new file mode 100644
index 000000000..f4547170c
--- /dev/null
+++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
@@ -0,0 +1,48 @@
+<%= if get_flash(@conn, :info) do %>
+ <%= get_flash(@conn, :info) %>
+<% end %>
+<%= if get_flash(@conn, :error) do %>
+ <%= get_flash(@conn, :error) %>
+<% end %>
+
+Registration Details
+
+If you'd like to register a new account,
+
+please provide the details below.
+
+
+<%= form_for @conn, o_auth_path(@conn, :register), [], fn f -> %>
+
+
+ <%= label f, :nickname, "Nickname" %>
+ <%= text_input f, :nickname, value: @nickname %>
+
+
+ <%= label f, :email, "Email" %>
+ <%= text_input f, :email, value: @email %>
+
+
+<%= submit "Proceed as new user", name: "op", value: "register" %>
+
+
+
+
+Alternatively, sign in to connect to existing account.
+
+
+ <%= label f, :auth_name, "Name or email" %>
+ <%= text_input f, :auth_name %>
+
+
+ <%= label f, :password, "Password" %>
+ <%= password_input f, :password %>
+
+
+<%= submit "Proceed as existing user", name: "op", value: "connect" %>
+
+<%= hidden_input f, :client_id, value: @client_id %>
+<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
+<%= hidden_input f, :scope, value: Enum.join(@scopes, " ") %>
+
+<% end %>
diff --git a/priv/repo/migrations/20190315101315_create_registrations.exs b/priv/repo/migrations/20190315101315_create_registrations.exs
index c566912f5..fbb22ec7c 100644
--- a/priv/repo/migrations/20190315101315_create_registrations.exs
+++ b/priv/repo/migrations/20190315101315_create_registrations.exs
@@ -2,7 +2,8 @@ defmodule Pleroma.Repo.Migrations.CreateRegistrations do
use Ecto.Migration
def change do
- create table(:registrations) do
+ create table(:registrations, primary_key: false) do
+ add :id, :uuid, primary_key: true
add :user_id, references(:users, type: :uuid, on_delete: :delete_all)
add :provider, :string
add :uid, :string
--
cgit v1.2.3
From af68a42ef7841013476831e92d3841088fa875df Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Wed, 20 Mar 2019 20:25:48 +0300
Subject: [#923] Support for multiple OAuth consumer strategies.
---
config/config.exs | 26 +++++++++++--------
lib/pleroma/web/oauth/oauth_controller.ex | 29 +++++++++++++++-------
.../web/templates/o_auth/o_auth/consumer.html.eex | 20 ++++++---------
.../web/templates/o_auth/o_auth/show.html.eex | 1 -
mix.exs | 13 ++++++----
mix.lock | 1 +
6 files changed, 53 insertions(+), 37 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 03baf894d..7d8de5af6 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -381,20 +381,26 @@ config :pleroma, :ldap,
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
uid: System.get_env("LDAP_UID") || "cn"
-config :pleroma, :auth, oauth_consumer_enabled: System.get_env("OAUTH_CONSUMER_ENABLED") == "true"
+oauth_consumer_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES" || ""))
+
+ueberauth_providers =
+ for strategy <- oauth_consumer_strategies do
+ strategy_module_name =
+ System.get_env("UEBERAUTH_#{String.upcase(strategy)}_STRATEGY_MODULE") ||
+ "Elixir.Ueberauth.Strategy.#{String.capitalize(strategy)}"
+
+ strategy_module = String.to_atom(strategy_module_name)
+ {String.to_atom(strategy), {strategy_module, [callback_params: ["state"]]}}
+ end
config :ueberauth,
Ueberauth,
base_path: "/oauth",
- providers: [
- twitter:
- {Ueberauth.Strategy.Twitter,
- [callback_params: ~w[client_id redirect_uri scope scopes]]}
- ]
-
-config :ueberauth, Ueberauth.Strategy.Twitter.OAuth,
- consumer_key: System.get_env("TWITTER_CONSUMER_KEY"),
- consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET")
+ providers: ueberauth_providers
+
+config :pleroma, :auth,
+ oauth_consumer_strategies: oauth_consumer_strategies,
+ oauth_consumer_enabled: oauth_consumer_strategies != []
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index a2c62ae68..b300c96df 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -187,25 +187,25 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|> redirect(to: "/")
end
- def callback(%{assigns: %{ueberauth_failure: failure}} = conn, %{"redirect_uri" => redirect_uri}) do
+ def callback(%{assigns: %{ueberauth_failure: failure}} = conn, params) do
+ params = callback_params(params)
messages = for e <- Map.get(failure, :errors, []), do: e.message
message = Enum.join(messages, "; ")
conn
|> put_flash(:error, "Failed to authenticate: #{message}.")
- |> redirect(external: redirect_uri(conn, redirect_uri))
+ |> redirect(external: redirect_uri(conn, params["redirect_uri"]))
end
- def callback(
- conn,
- %{"client_id" => client_id, "redirect_uri" => redirect_uri} = params
- ) do
+ def callback(conn, params) do
+ params = callback_params(params)
+
with {:ok, registration} <- Authenticator.get_registration(conn, params) do
user = Repo.preload(registration, :user).user
auth_params = %{
- "client_id" => client_id,
- "redirect_uri" => redirect_uri,
+ "client_id" => params["client_id"],
+ "redirect_uri" => params["redirect_uri"],
"scopes" => oauth_scopes(params, nil)
}
@@ -230,10 +230,21 @@ defmodule Pleroma.Web.OAuth.OAuthController do
_ ->
conn
|> put_flash(:error, "Failed to set up user account.")
- |> redirect(external: redirect_uri(conn, redirect_uri))
+ |> redirect(external: redirect_uri(conn, params["redirect_uri"]))
end
end
+ defp callback_params(%{"state" => state} = params) do
+ [client_id, redirect_uri, scope, state] = String.split(state, "|")
+
+ Map.merge(params, %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri,
+ "scope" => scope,
+ "state" => state
+ })
+ end
+
def registration_details(conn, params) do
render(conn, "register.html", %{
client_id: params["client_id"],
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
index e7251bce8..a64859a49 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
@@ -1,14 +1,10 @@
-External OAuth Authorization
-<%= form_for @conn, o_auth_path(@conn, :request, :twitter), [method: "get"], fn f -> %>
-
+
+
+Sign in with external provider
- <%= hidden_input f, :client_id, value: @client_id %>
- <%= hidden_input f, :redirect_uri, value: @redirect_uri %>
- <%= hidden_input f, :state, value: @state%>
- <%= submit "Sign in with Twitter" %>
+<%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %>
+ <%= form_for @conn, o_auth_path(@conn, :request, strategy), [method: "get"], fn f -> %>
+ <%= hidden_input f, :state, value: Enum.join([@client_id, @redirect_uri, Enum.join(@available_scopes, " "), @state], "|") %>
+ <%= submit "Sign in with #{String.capitalize(strategy)}" %>
+ <% end %>
<% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index 2fa7837fc..b2381869a 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -37,6 +37,5 @@
<% end %>
<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %>
-
<%= render @view_module, "consumer.html", assigns %>
<% end %>
diff --git a/mix.exs b/mix.exs
index 25711bc26..f7ab008ac 100644
--- a/mix.exs
+++ b/mix.exs
@@ -44,7 +44,7 @@ defmodule Pleroma.Mixfile do
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin, :ueberauth_twitter],
+ extra_applications: [:logger, :runtime_tools, :comeonin],
included_applications: [:ex_syslogger]
]
end
@@ -57,6 +57,12 @@ defmodule Pleroma.Mixfile do
#
# Type `mix help deps` for examples and options.
defp deps do
+ oauth_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES") || "")
+
+ oauth_deps =
+ for s <- oauth_strategies,
+ do: {String.to_atom("ueberauth_#{s}"), ">= 0.0.0"}
+
[
{:phoenix, "~> 1.4.1"},
{:plug_cowboy, "~> 2.0"},
@@ -94,14 +100,11 @@ defmodule Pleroma.Mixfile do
{:floki, "~> 0.20.0"},
{:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"},
{:timex, "~> 3.5"},
- {:oauth, github: "tim/erlang-oauth"},
- # {:oauth2, "~> 0.8", override: true},
{:ueberauth, "~> 0.4"},
- {:ueberauth_twitter, "~> 0.2"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}
- ]
+ ] ++ oauth_deps
end
# Aliases are shortcuts or tasks specific to the current project.
diff --git a/mix.lock b/mix.lock
index 92660b70a..6a6cee1a9 100644
--- a/mix.lock
+++ b/mix.lock
@@ -67,6 +67,7 @@
"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"},
"ueberauth": {:hex, :ueberauth, "0.5.0", "4570ec94d7f784dc4c4aa94c83391dbd9b9bd7b66baa30e95a666c5ec1b168b1", [:mix], [{:plug, "~> 1.2", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+ "ueberauth_facebook": {:hex, :ueberauth_facebook, "0.8.0", "9ec8571f804dd5c06f4e305d70606b39fc0ac8a8f43ed56ebb76012a97d14729", [:mix], [{:oauth2, "~> 0.9", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.4", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm"},
"ueberauth_twitter": {:hex, :ueberauth_twitter, "0.2.4", "770ac273cc696cde986582e7a36df0923deb39fa3deff0152fbf150343809f81", [:mix], [{:httpoison, "~> 0.7", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:poison, "~> 1.3 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.2", [hex: :ueberauth, 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"},
--
cgit v1.2.3
From 81bf6d9e6a92b4af00b3351b043193a3c299ede5 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Wed, 20 Mar 2019 20:29:08 +0300
Subject: [#923] Typo fix.
---
config/config.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/config.exs b/config/config.exs
index 7d8de5af6..586844516 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -381,7 +381,7 @@ config :pleroma, :ldap,
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
uid: System.get_env("LDAP_UID") || "cn"
-oauth_consumer_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES" || ""))
+oauth_consumer_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGIES") || "")
ueberauth_providers =
for strategy <- oauth_consumer_strategies do
--
cgit v1.2.3
From 2a95014b9d7142aa2549e70f428293af78fae8eb Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Wed, 27 Mar 2019 15:39:35 +0300
Subject: [#923] OAuth consumer improvements, fixes, refactoring.
---
config/config.exs | 5 +---
lib/pleroma/web/auth/authenticator.ex | 6 +++++
lib/pleroma/web/auth/ldap_authenticator.ex | 2 ++
lib/pleroma/web/auth/pleroma_authenticator.ex | 2 ++
lib/pleroma/web/oauth/oauth_controller.ex | 28 +++++++++++++++-------
lib/pleroma/web/router.ex | 1 +
.../web/templates/o_auth/o_auth/_scopes.html.eex | 13 ++++++++++
.../web/templates/o_auth/o_auth/consumer.html.eex | 15 ++++++++----
.../web/templates/o_auth/o_auth/show.html.eex | 16 +++----------
mix.lock | 7 +-----
10 files changed, 59 insertions(+), 36 deletions(-)
create mode 100644 lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
diff --git a/config/config.exs b/config/config.exs
index 586844516..bdaf5205a 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -385,10 +385,7 @@ oauth_consumer_strategies = String.split(System.get_env("OAUTH_CONSUMER_STRATEGI
ueberauth_providers =
for strategy <- oauth_consumer_strategies do
- strategy_module_name =
- System.get_env("UEBERAUTH_#{String.upcase(strategy)}_STRATEGY_MODULE") ||
- "Elixir.Ueberauth.Strategy.#{String.capitalize(strategy)}"
-
+ strategy_module_name = "Elixir.Ueberauth.Strategy.#{String.capitalize(strategy)}"
strategy_module = String.to_atom(strategy_module_name)
{String.to_atom(strategy), {strategy_module, [callback_params: ["state"]]}}
end
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index 1f614668c..bb87b323c 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -33,4 +33,10 @@ defmodule Pleroma.Web.Auth.Authenticator do
def auth_template do
implementation().auth_template() || Pleroma.Config.get(:auth_template, "show.html")
end
+
+ @callback oauth_consumer_template() :: String.t() | nil
+ def oauth_consumer_template do
+ implementation().oauth_consumer_template() ||
+ Pleroma.Config.get(:oauth_consumer_template, "consumer.html")
+ end
end
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 65abd7f38..8b6d5a77f 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -51,6 +51,8 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
def auth_template, do: nil
+ def oauth_consumer_template, do: nil
+
defp ldap_user(name, password) do
ldap = Pleroma.Config.get(:ldap, [])
host = Keyword.get(ldap, :host, "localhost")
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 60847ce6a..8b190f97f 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -92,4 +92,6 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
end
def auth_template, do: nil
+
+ def oauth_consumer_template, do: nil
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index b300c96df..078839d5c 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -174,6 +174,25 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
+ def prepare_request(conn, %{"provider" => provider} = params) do
+ scope =
+ oauth_scopes(params, [])
+ |> Enum.join(" ")
+
+ state =
+ params
+ |> Map.delete("scopes")
+ |> Map.put("scope", scope)
+ |> Poison.encode!()
+
+ params =
+ params
+ |> Map.drop(~w(scope scopes client_id redirect_uri))
+ |> Map.put("state", state)
+
+ redirect(conn, to: o_auth_path(conn, :request, provider, params))
+ end
+
def request(conn, params) do
message =
if params["provider"] do
@@ -235,14 +254,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
defp callback_params(%{"state" => state} = params) do
- [client_id, redirect_uri, scope, state] = String.split(state, "|")
-
- Map.merge(params, %{
- "client_id" => client_id,
- "redirect_uri" => redirect_uri,
- "scope" => scope,
- "state" => state
- })
+ Map.merge(params, Poison.decode!(state))
end
def registration_details(conn, params) do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index f2cec574b..4d0e04d9f 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -213,6 +213,7 @@ defmodule Pleroma.Web.Router do
scope [] do
pipe_through(:browser)
+ get("/prepare_request", OAuthController, :prepare_request)
get("/:provider", OAuthController, :request)
get("/:provider/callback", OAuthController, :callback)
post("/register", OAuthController, :register)
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
new file mode 100644
index 000000000..4b8fb5dae
--- /dev/null
+++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
@@ -0,0 +1,13 @@
+
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
index a64859a49..002f014e6 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
@@ -2,9 +2,14 @@
Sign in with external provider
-<%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %>
- <%= form_for @conn, o_auth_path(@conn, :request, strategy), [method: "get"], fn f -> %>
- <%= hidden_input f, :state, value: Enum.join([@client_id, @redirect_uri, Enum.join(@available_scopes, " "), @state], "|") %>
- <%= submit "Sign in with #{String.capitalize(strategy)}" %>
- <% end %>
+<%= form_for @conn, o_auth_path(@conn, :prepare_request), [method: "get"], fn f -> %>
+ <%= render @view_module, "_scopes.html", Map.put(assigns, :form, f) %>
+
+ <%= hidden_input f, :client_id, value: @client_id %>
+ <%= hidden_input f, :redirect_uri, value: @redirect_uri %>
+ <%= hidden_input f, :state, value: @state %>
+
+ <%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %>
+ <%= submit "Sign in with #{String.capitalize(strategy)}", name: "provider", value: strategy %>
+ <% end %>
<% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index b2381869a..e6cf1db45 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -16,18 +16,8 @@
<%= label f, :password, "Password" %>
<%= password_input f, :password %>
-
+
+<%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f, scope_param: "authorization[scope][]"}) %>
<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :response_type, value: @response_type %>
@@ -37,5 +27,5 @@
<% end %>
<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %>
- <%= render @view_module, "consumer.html", assigns %>
+ <%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %>
<% end %>
diff --git a/mix.lock b/mix.lock
index 6a6cee1a9..ee8617124 100644
--- a/mix.lock
+++ b/mix.lock
@@ -43,9 +43,6 @@
"mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
- "oauth": {:git, "https://github.com/tim/erlang-oauth.git", "bd19896e31125f99ff45bb5850b1c0e74b996743", []},
- "oauth2": {:hex, :oauth2, "0.9.4", "632e8e8826a45e33ac2ea5ac66dcc019ba6bb5a0d2ba77e342d33e3b7b252c6e", [:mix], [{:hackney, "~> 1.7", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
- "oauther": {:hex, :oauther, "1.1.1", "7d8b16167bb587ecbcddd3f8792beb9ec3e7b65c1f8ebd86b8dd25318d535752", [: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"},
@@ -66,9 +63,7 @@
"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"},
- "ueberauth": {:hex, :ueberauth, "0.5.0", "4570ec94d7f784dc4c4aa94c83391dbd9b9bd7b66baa30e95a666c5ec1b168b1", [:mix], [{:plug, "~> 1.2", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
- "ueberauth_facebook": {:hex, :ueberauth_facebook, "0.8.0", "9ec8571f804dd5c06f4e305d70606b39fc0ac8a8f43ed56ebb76012a97d14729", [:mix], [{:oauth2, "~> 0.9", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.4", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm"},
- "ueberauth_twitter": {:hex, :ueberauth_twitter, "0.2.4", "770ac273cc696cde986582e7a36df0923deb39fa3deff0152fbf150343809f81", [:mix], [{:httpoison, "~> 0.7", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:poison, "~> 1.3 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.2", [hex: :ueberauth, 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"},
"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"},
--
cgit v1.2.3
From 642075b1a935c42181a10ea695b2289883126136 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Wed, 27 Mar 2019 16:20:50 +0300
Subject: [#923] Enabled binding of multiple OAuth provider accounts to single
user.
---
priv/repo/migrations/20190315101315_create_registrations.exs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/priv/repo/migrations/20190315101315_create_registrations.exs b/priv/repo/migrations/20190315101315_create_registrations.exs
index fbb22ec7c..6b28cbdd3 100644
--- a/priv/repo/migrations/20190315101315_create_registrations.exs
+++ b/priv/repo/migrations/20190315101315_create_registrations.exs
@@ -13,6 +13,6 @@ defmodule Pleroma.Repo.Migrations.CreateRegistrations do
end
create unique_index(:registrations, [:provider, :uid])
- create unique_index(:registrations, [:user_id, :provider])
+ create unique_index(:registrations, [:user_id, :provider, :uid])
end
end
--
cgit v1.2.3
From 1bb4d5d65be725f374e06da88a5e8e826660596b Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 29 Mar 2019 21:59:04 +0300
Subject: Implement fake status submit
---
lib/pleroma/web/activity_pub/activity_pub.ex | 31 ++++++++++++----
lib/pleroma/web/common_api/common_api.ex | 17 +++++----
.../mastodon_api/mastodon_api_controller_test.exs | 42 ++++++++++++++++++++++
3 files changed, 76 insertions(+), 14 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 6e1ed7ec9..b459fd882 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -113,15 +113,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def decrease_replies_count_if_reply(_object), do: :noop
- def insert(map, local \\ true) when is_map(map) do
+ def insert(map, local \\ true, fake \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map),
:ok <- check_actor_is_active(map["actor"]),
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
+ {recipients, _, _} = get_recipients(map),
+ {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
{:ok, object} <- insert_full_object(map) do
- {recipients, _, _} = get_recipients(map)
-
{:ok, activity} =
Repo.insert(%Activity{
data: map,
@@ -146,8 +146,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
stream_out(activity)
{:ok, activity}
else
- %Activity{} = activity -> {:ok, activity}
- error -> {:error, error}
+ %Activity{} = activity ->
+ {:ok, activity}
+
+ {:fake, true, map, recipients} ->
+ {:ok,
+ %Activity{
+ data: map,
+ local: local,
+ actor: map["actor"],
+ recipients: recipients,
+ id: "pleroma:fakeid"
+ }}
+
+ error ->
+ {:error, error}
end
end
@@ -190,7 +203,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- def create(%{to: to, actor: actor, context: context, object: object} = params) do
+ def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do
additional = params[:additional] || %{}
# only accept false as false value
local = !(params[:local] == false)
@@ -201,13 +214,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
%{to: to, actor: actor, published: published, context: context, object: object},
additional
),
- {:ok, activity} <- insert(create_data, local),
+ {:ok, activity} <- insert(create_data, local, fake),
+ {:fake, false, activity} <- {:fake, fake, activity},
_ <- increase_replies_count_if_reply(create_data),
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
+ else
+ {:fake, true, activity} ->
+ {:ok, activity}
end
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 25b990677..8e2937ac5 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -172,13 +172,16 @@ defmodule Pleroma.Web.CommonAPI do
end)
) do
res =
- ActivityPub.create(%{
- to: to,
- actor: user,
- context: context,
- object: object,
- additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
- })
+ ActivityPub.create(
+ %{
+ to: to,
+ actor: user,
+ context: context,
+ object: object,
+ additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
+ },
+ data["fake"] || false
+ )
res
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..3395c3689 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -143,6 +143,48 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert Repo.get(Activity, id)
end
+ test "posting a fake status", %{conn: conn} do
+ user = insert(:user)
+
+ real_conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
+ })
+
+ real_status =
+ json_response(real_conn, 200)
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ assert real_status
+
+ fake_conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
+ "fake" => true
+ })
+
+ fake_status =
+ json_response(fake_conn, 200)
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ assert fake_status
+ assert real_status == fake_status
+ end
+
test "posting a status with OGP link preview", %{conn: conn} do
Pleroma.Config.put([:rich_media, :enabled], true)
user = insert(:user)
--
cgit v1.2.3
From 42b779527c551595399771fbc3c0701d38a3ed3d Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 29 Mar 2019 22:15:20 +0300
Subject: document fake option
---
docs/api/differences_in_mastoapi_responses.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md
index d993d1383..f5ce7493d 100644
--- a/docs/api/differences_in_mastoapi_responses.md
+++ b/docs/api/differences_in_mastoapi_responses.md
@@ -44,3 +44,9 @@ Has these additional fields under the `pleroma` object:
Has these additional fields under the `pleroma` object:
- `is_seen`: true if the notification was read by the user
+
+## POST `/api/v1/statuses`
+
+Additional parameters can be added to the JSON body:
+
+- `fake`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
--
cgit v1.2.3
From cd387f8693c57b925576ab92f8202ef28007cfc0 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Sat, 30 Mar 2019 13:57:54 +0300
Subject: Add a fake option to lazy_put_actvity_defaults
---
lib/pleroma/web/activity_pub/activity_pub.ex | 2 +-
lib/pleroma/web/activity_pub/utils.ex | 34 +++++++++++++++++-----------
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index b459fd882..a94040d01 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def insert(map, local \\ true, fake \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
- map <- lazy_put_activity_defaults(map),
+ map <- lazy_put_activity_defaults(map, fake),
:ok <- check_actor_is_active(map["actor"]),
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 2e9ffe41c..3959e9bd9 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -175,21 +175,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do
Adds an id and a published data if they aren't there,
also adds it to an included object
"""
- def lazy_put_activity_defaults(map) do
- %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
-
- map =
- map
- |> Map.put_new_lazy("id", &generate_activity_id/0)
- |> Map.put_new_lazy("published", &make_date/0)
- |> Map.put_new("context", context)
- |> Map.put_new("context_id", context_id)
-
- if is_map(map["object"]) do
- object = lazy_put_object_defaults(map["object"], map)
- %{map | "object" => object}
+ def lazy_put_activity_defaults(map, fake \\ false) do
+ unless fake do
+ %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
+
+ map =
+ map
+ |> Map.put_new_lazy("id", &generate_activity_id/0)
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("context", context)
+ |> Map.put_new("context_id", context_id)
+
+ if is_map(map["object"]) do
+ object = lazy_put_object_defaults(map["object"], map)
+ %{map | "object" => object}
+ else
+ map
+ end
else
map
+ |> Map.put_new("id", "pleroma:fakeid")
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("context", "pleroma:fakecontext")
+ |> Map.put_new("context_id", -1)
end
end
--
cgit v1.2.3
From 32e843f033bf10ab98213a3292d411ab33f9a85a Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 00:30:21 +0200
Subject: CC-BY-SA-4.0: Add a copy of the CC-BY-SA-4.0 license
[ci skip]
---
CC-BY-SA-4.0 | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 427 insertions(+)
create mode 100644 CC-BY-SA-4.0
diff --git a/CC-BY-SA-4.0 b/CC-BY-SA-4.0
new file mode 100644
index 000000000..4681ab80f
--- /dev/null
+++ b/CC-BY-SA-4.0
@@ -0,0 +1,427 @@
+Attribution-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. BY-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative
+ Commons as essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name
+ of a Creative Commons Public License. The License Elements of this
+ Public License are Attribution and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ l. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ m. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. Additional offer from the Licensor -- Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor to
+ exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter's License You apply.
+
+ c. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ b. ShareAlike.
+
+ In addition to the conditions in Section 3(a), if You Share
+ Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter's License You apply must be a Creative Commons
+ license with the same License Elements, this version or
+ later, or a BY-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition
+ in any reasonable manner based on the medium, means, and
+ context in which You Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological
+ Measures to, Adapted Material that restrict exercise of the
+ rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material,
+ including for purposes of Section 3(b); and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
--
cgit v1.2.3
From 362603c7235994ef5fccc3950ab90ff6be2b8b18 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 00:31:21 +0200
Subject: =?UTF-8?q?LICENSE=20=E2=86=92=20AGPL-3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[ci skip]
---
AGPL-3 | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LICENSE | 661 ----------------------------------------------------------------
2 files changed, 661 insertions(+), 661 deletions(-)
create mode 100644 AGPL-3
delete mode 100644 LICENSE
diff --git a/AGPL-3 b/AGPL-3
new file mode 100644
index 000000000..0bf239554
--- /dev/null
+++ b/AGPL-3
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ Pleroma
+ Copyright (C) 2017 Roger Braun
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+ .
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 0bf239554..000000000
--- a/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- Pleroma
- Copyright (C) 2017 Roger Braun
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
- .
--
cgit v1.2.3
From 8ae4837abdcb74b570b4257f0afd9a1f5296726f Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 00:32:00 +0200
Subject: COPYING: Add copyright notice for the whole repository
[ci skip]
---
COPYING | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 COPYING
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..85a285932
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,18 @@
+Unless otherwise stated this repository is copyright © 2017-2019 Pleroma Authors , and is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file in AGPL-3.
+
+---
+
+The following files are copyright © 2019 shitposter.club, and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file into CC-BY-SA-4.0.
+
+priv/static/images/pleroma-fox-tan.png
+priv/static/images/pleroma-fox-tan-smol.png
+priv/static/images/pleroma-tan.png
+
+---
+
+The following files are copyright © 2017-2019 Pleroma Authors , and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file into CC-BY-SA-4.0.
+
+priv/static/images/avi.png
+priv/static/images/banner.png
+priv/static/images/city.jpg
+priv/static/instance/thumbnail.jpeg
--
cgit v1.2.3
From 0bab2661ae8e0a28958fa02cf67377e7a9f88ebb Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 02:15:14 +0200
Subject: COPYING: Add copyright notice for the finmojis
[ci skip]
---
CC-BY-NC-ND-4.0 | 403 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
COPYING | 4 +
2 files changed, 407 insertions(+)
create mode 100644 CC-BY-NC-ND-4.0
diff --git a/CC-BY-NC-ND-4.0 b/CC-BY-NC-ND-4.0
new file mode 100644
index 000000000..486544290
--- /dev/null
+++ b/CC-BY-NC-ND-4.0
@@ -0,0 +1,403 @@
+Attribution-NonCommercial-NoDerivatives 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
+International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-NoDerivatives 4.0 International Public
+License ("Public License"). To the extent this Public License may be
+interpreted as a contract, You are granted the Licensed Rights in
+consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the
+Licensor receives from making the Licensed Material available under
+these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ c. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ d. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ e. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ f. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ g. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ h. NonCommercial means not primarily intended for or directed towards
+ commercial advantage or monetary compensation. For purposes of
+ this Public License, the exchange of the Licensed Material for
+ other material subject to Copyright and Similar Rights by digital
+ file-sharing or similar means is NonCommercial provided there is
+ no payment of monetary compensation in connection with the
+ exchange.
+
+ i. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ j. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ k. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part, for NonCommercial purposes only; and
+
+ b. produce and reproduce, but not Share, Adapted Material
+ for NonCommercial purposes only.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties, including when
+ the Licensed Material is used other than for NonCommercial
+ purposes.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material, You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ For the avoidance of doubt, You do not have permission under
+ this Public License to Share Adapted Material.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database for NonCommercial purposes
+ only and provided You do not Share Adapted Material;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material; and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
+
diff --git a/COPYING b/COPYING
index 85a285932..2275071a4 100644
--- a/COPYING
+++ b/COPYING
@@ -16,3 +16,7 @@ priv/static/images/avi.png
priv/static/images/banner.png
priv/static/images/city.jpg
priv/static/instance/thumbnail.jpeg
+
+---
+
+The files present under the priv/static/finmoji directory are copyright Finland , and are distributed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International license, you should have received a copy of the license file into CC-BY-NC-ND-4.0.
--
cgit v1.2.3
From eadafc88b898879eb50545b700ea13c8596e908b Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 1 Apr 2019 09:28:56 +0300
Subject: [#923] Deps config adjustment (no `override` for `httpoison`), code
analysis issues fixes.
---
lib/pleroma/web/auth/pleroma_authenticator.ex | 2 +-
lib/pleroma/web/endpoint.ex | 3 ++-
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
mix.exs | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 8b190f97f..c826adb4c 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -4,9 +4,9 @@
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Comeonin.Pbkdf2
- alias Pleroma.User
alias Pleroma.Registration
alias Pleroma.Repo
+ alias Pleroma.User
@behaviour Pleroma.Web.Auth.Authenticator
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index f92724d8b..b85b95bf9 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -60,7 +60,8 @@ defmodule Pleroma.Web.Endpoint do
same_site =
if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do
- # Note: "SameSite=Strict" prevents sign in with external OAuth provider (no cookies during callback request)
+ # Note: "SameSite=Strict" prevents sign in with external OAuth provider
+ # (there would be no cookies during callback request from OAuth provider)
"SameSite=Lax"
else
"SameSite=Strict"
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index e54e196aa..54e0a35ba 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,9 +5,9 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
+ alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Registration
alias Pleroma.Web.Auth.Authenticator
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
diff --git a/mix.exs b/mix.exs
index 34c17bd6b..2b0d25b55 100644
--- a/mix.exs
+++ b/mix.exs
@@ -76,7 +76,7 @@ defmodule Pleroma.Mixfile do
{:phoenix_html, "~> 2.10"},
{:calendar, "~> 0.17.4"},
{:cachex, "~> 3.0.2"},
- {:httpoison, "~> 1.2.0", override: true},
+ {:httpoison, "~> 1.2.0"},
{:poison, "~> 3.0", override: true},
{:tesla, "~> 1.2"},
{:jason, "~> 1.0"},
--
cgit v1.2.3
From 804173fc924ec591558b8ed7671e35b506be9345 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 1 Apr 2019 09:45:44 +0300
Subject: [#923] Minor code readability fix.
---
lib/pleroma/web/auth/authenticator.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index bb87b323c..4eeef5034 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.Authenticator do
- alias Pleroma.User
alias Pleroma.Registration
+ alias Pleroma.User
def implementation do
Pleroma.Config.get(
--
cgit v1.2.3
From 45ba10bf47baf350fd4d538cbe32cec447d496e6 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 1 Apr 2019 11:55:59 +0300
Subject: Fix the issue with HTML scrubber
---
lib/pleroma/html.ex | 17 +++++++++++++++--
lib/pleroma/object.ex | 5 +++++
lib/pleroma/web/activity_pub/activity_pub.ex | 22 ++++++++++++++--------
3 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 5b152d926..f19b42b42 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -28,9 +28,13 @@ defmodule Pleroma.HTML do
def filter_tags(html), do: filter_tags(html, nil)
def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags)
+ # TODO: rename object to activity because that's what it is really working with
def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do
key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}"
- Cachex.fetch!(:scrubber_cache, key, fn _key -> ensure_scrubbed_html(content, scrubbers) end)
+
+ Cachex.fetch!(:scrubber_cache, key, fn _key ->
+ ensure_scrubbed_html(content, scrubbers, object.data["object"]["fake"] || false)
+ end)
end
def get_cached_stripped_html_for_object(content, object, module) do
@@ -44,11 +48,20 @@ defmodule Pleroma.HTML do
def ensure_scrubbed_html(
content,
- scrubbers
+ scrubbers,
+ _fake = false
) do
{:commit, filter_tags(content, scrubbers)}
end
+ def ensure_scrubbed_html(
+ content,
+ scrubbers,
+ _fake = true
+ ) do
+ {:ignore, filter_tags(content, scrubbers)}
+ end
+
defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do
generate_scrubber_signature([scrubber])
end
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 8a670645d..013d62157 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -44,6 +44,11 @@ defmodule Pleroma.Object do
# Use this whenever possible, especially when walking graphs in an O(N) loop!
def normalize(%Activity{object: %Object{} = object}), do: object
+ # A hack for fake activities
+ def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}) do
+ %Object{id: "pleroma:fake_object_id", data: data}
+ end
+
# Catch and log Object.normalize() calls where the Activity's child object is not
# preloaded.
def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}) do
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index a94040d01..716a40419 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -150,14 +150,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, activity}
{:fake, true, map, recipients} ->
- {:ok,
- %Activity{
- data: map,
- local: local,
- actor: map["actor"],
- recipients: recipients,
- id: "pleroma:fakeid"
- }}
+ map =
+ map
+ |> put_in(["object", "fake"], true)
+
+ activity = %Activity{
+ data: map,
+ local: local,
+ actor: map["actor"],
+ recipients: recipients,
+ id: "pleroma:fakeid"
+ }
+
+ # Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ {:ok, activity}
error ->
{:error, error}
--
cgit v1.2.3
From d866b59eeaed25a1ad19581bd6c942f9f2d2711e Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 1 Apr 2019 11:58:08 +0300
Subject: oof
---
lib/pleroma/web/activity_pub/activity_pub.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 716a40419..9cb4a0542 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -162,7 +162,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
id: "pleroma:fakeid"
}
- # Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
{:ok, activity}
error ->
--
cgit v1.2.3
From 975482f091f2f957c138d1b4f2d37e6b5d2b82a8 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 1 Apr 2019 12:16:51 +0300
Subject: insert object defaults for fake activities and make credo happy
---
lib/pleroma/html.ex | 4 ++--
lib/pleroma/web/activity_pub/utils.ex | 34 ++++++++++++++++++++++------------
2 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index f19b42b42..1e48749a8 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -49,7 +49,7 @@ defmodule Pleroma.HTML do
def ensure_scrubbed_html(
content,
scrubbers,
- _fake = false
+ false = _fake
) do
{:commit, filter_tags(content, scrubbers)}
end
@@ -57,7 +57,7 @@ defmodule Pleroma.HTML do
def ensure_scrubbed_html(
content,
scrubbers,
- _fake = true
+ true = _fake
) do
{:ignore, filter_tags(content, scrubbers)}
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 3959e9bd9..feb73518e 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -176,35 +176,45 @@ defmodule Pleroma.Web.ActivityPub.Utils do
also adds it to an included object
"""
def lazy_put_activity_defaults(map, fake \\ false) do
- unless fake do
- %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
+ map =
+ unless fake do
+ %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
- map =
map
|> Map.put_new_lazy("id", &generate_activity_id/0)
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new("context", context)
|> Map.put_new("context_id", context_id)
-
- if is_map(map["object"]) do
- object = lazy_put_object_defaults(map["object"], map)
- %{map | "object" => object}
else
map
+ |> Map.put_new("id", "pleroma:fakeid")
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("context", "pleroma:fakecontext")
+ |> Map.put_new("context_id", -1)
end
+
+ if is_map(map["object"]) do
+ object = lazy_put_object_defaults(map["object"], map, fake)
+ %{map | "object" => object}
else
map
- |> Map.put_new("id", "pleroma:fakeid")
- |> Map.put_new_lazy("published", &make_date/0)
- |> Map.put_new("context", "pleroma:fakecontext")
- |> Map.put_new("context_id", -1)
end
end
@doc """
Adds an id and published date if they aren't there.
"""
- def lazy_put_object_defaults(map, activity \\ %{}) do
+ def lazy_put_object_defaults(map, activity \\ %{}, fake)
+
+ def lazy_put_object_defaults(map, activity, true = _fake) do
+ map
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("id", "pleroma:fakeid")
+ |> Map.put_new("context", activity["context"])
+ |> Map.put_new("context_id", activity["context_id"])
+ end
+
+ def lazy_put_object_defaults(map, activity, _fake) do
map
|> Map.put_new_lazy("id", &generate_object_id/0)
|> Map.put_new_lazy("published", &make_date/0)
--
cgit v1.2.3
From fe5145eeaab81573614a3475463a24229a6a58a3 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 1 Apr 2019 12:25:53 +0300
Subject: Move putting fake attribute to lib/pleroma/web/activity_pub/utils.ex
---
lib/pleroma/web/activity_pub/activity_pub.ex | 4 ----
lib/pleroma/web/activity_pub/utils.ex | 3 ++-
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 9cb4a0542..f217e7bac 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -150,10 +150,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, activity}
{:fake, true, map, recipients} ->
- map =
- map
- |> put_in(["object", "fake"], true)
-
activity = %Activity{
data: map,
local: local,
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index feb73518e..d22da6f40 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -209,8 +209,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def lazy_put_object_defaults(map, activity, true = _fake) do
map
|> Map.put_new_lazy("published", &make_date/0)
- |> Map.put_new("id", "pleroma:fakeid")
+ |> Map.put_new("id", "pleroma:fake_object_id")
|> Map.put_new("context", activity["context"])
+ |> Map.put_new("fake", true)
|> Map.put_new("context_id", activity["context_id"])
end
--
cgit v1.2.3
From 3601f03147bd104f6acff64e7c8d5d4d3e1f53a2 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Mon, 1 Apr 2019 17:17:57 +0700
Subject: Adding tag to emoji ets table
changes in apis
---
config/config.exs | 7 ++-
config/emoji.txt | 5 +-
docs/api/pleroma_api.md | 6 +--
docs/config/custom_emoji.md | 24 +++++++++-
lib/pleroma/emoji.ex | 53 +++++++++++++++++++---
lib/pleroma/formatter.ex | 8 ++--
lib/pleroma/web/common_api/common_api.ex | 2 +-
lib/pleroma/web/common_api/utils.ex | 2 +-
.../web/mastodon_api/mastodon_api_controller.ex | 5 +-
.../web/twitter_api/controllers/util_controller.ex | 8 +++-
test/emoji_test.exs | 30 ++++++++++++
test/formatter_test.exs | 3 +-
.../mastodon_api/mastodon_api_controller_test.exs | 16 +++++++
test/web/twitter_api/util_controller_test.exs | 21 +++++++++
14 files changed, 165 insertions(+), 25 deletions(-)
create mode 100644 test/emoji_test.exs
diff --git a/config/config.exs b/config/config.exs
index 0df38d75a..245c7d268 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -54,7 +54,12 @@ config :pleroma, Pleroma.Uploaders.MDII,
cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi",
files: "https://mdii.sakura.ne.jp"
-config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"]
+config :pleroma, :emoji,
+ shortcode_globs: ["/emoji/custom/**/*.png"],
+ custom_tag: "Custom",
+ finmoji_tag: "Finmoji",
+ emoji_tag: "Emoji",
+ custom_emoji_tag: "Custom"
config :pleroma, :uri_schemes,
valid_schemes: [
diff --git a/config/emoji.txt b/config/emoji.txt
index 7afacb09f..79246f239 100644
--- a/config/emoji.txt
+++ b/config/emoji.txt
@@ -1,5 +1,5 @@
-firefox, /emoji/Firefox.gif
-blank, /emoji/blank.png
+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
@@ -28,4 +28,3 @@ 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/docs/api/pleroma_api.md b/docs/api/pleroma_api.md
index 478c9d874..2e8fb04d2 100644
--- a/docs/api/pleroma_api.md
+++ b/docs/api/pleroma_api.md
@@ -10,7 +10,7 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
* Authentication: not required
* Params: none
* Response: JSON
-* Example response: `{"kalsarikannit_f":"/finmoji/128px/kalsarikannit_f-128.png","perkele":"/finmoji/128px/perkele-128.png","blobdab":"/emoji/blobdab.png","happiness":"/finmoji/128px/happiness-128.png"}`
+* Example response: `[{"kalsarikannit_f":{"tags":["Finmoji"],"image_url":"/finmoji/128px/kalsarikannit_f-128.png"}},{"perkele":{"tags":["Finmoji"],"image_url":"/finmoji/128px/perkele-128.png"}},{"blobdab":{"tags":["SomeTag"],"image_url":"/emoji/blobdab.png"}},"happiness":{"tags":["Finmoji"],"image_url":"/finmoji/128px/happiness-128.png"}}]`
* Note: Same data as Mastodon API’s `/api/v1/custom_emojis` but in a different format
## `/api/pleroma/follow_import`
@@ -27,14 +27,14 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
* Method: `GET`
* Authentication: not required
* Params: none
-* Response: Provider specific JSON, the only guaranteed parameter is `type`
+* Response: Provider specific JSON, the only guaranteed parameter is `type`
* Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint"}`
## `/api/pleroma/delete_account`
### Delete an account
* Method `POST`
* Authentication: required
-* Params:
+* Params:
* `password`: user's password
* Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise
* Example response: `{"error": "Invalid password."}`
diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md
index e833d2080..e47a75c8e 100644
--- a/docs/config/custom_emoji.md
+++ b/docs/config/custom_emoji.md
@@ -11,8 +11,28 @@ image files (in `/priv/static/emoji/custom`): `happy.png` and `sad.png`
content of `config/custom_emoji.txt`:
```
-happy, /emoji/custom/happy.png
-sad, /emoji/custom/sad.png
+happy, /emoji/custom/happy.png, Tag1,Tag2
+sad, /emoji/custom/sad.png, Tag1
+foo, /emoji/custom/foo.png
```
The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon.
+
+# Emoji tags
+
+Changing default tags:
+
+* For `Finmoji`, `emoji.txt` and `custom_emoji.txt` are added default tags, which can be configured in the `config.exs`:
+* For emoji loaded from globs:
+ - `priv/static/emoji/custom/*.png` - `custom_tag`, can be configured in `config.exs`
+ - `priv/static/emoji/custom/TagName/*.png` - folder (`TagName`) is used as tag
+
+
+```
+config :pleroma, :emoji,
+ shortcode_globs: ["/emoji/custom/**/*.png"],
+ custom_tag: "Custom", # Default tag for emoji in `priv/static/emoji/custom` path
+ finmoji_tag: "Finmoji", # Default tag for Finmoji
+ emoji_tag: "Emoji", # Default tag for emoji.txt
+ custom_emoji_tag: "Custom" # Default tag for custom_emoji.txt
+```
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index f3f08cd9d..c35aed6ee 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.Emoji do
* the built-in Finmojis (if enabled in configuration),
* the files: `config/emoji.txt` and `config/custom_emoji.txt`
- * glob paths
+ * glob paths, nested folder is used as tag name for grouping e.g. priv/static/emoji/custom/nested_folder
This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime.
"""
@@ -152,8 +152,10 @@ defmodule Pleroma.Emoji do
"woollysocks"
]
defp load_finmoji(true) do
+ tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
+
Enum.map(@finmoji, fn finmoji ->
- {finmoji, "/finmoji/128px/#{finmoji}-128.png"}
+ {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag}
end)
end
@@ -168,31 +170,70 @@ defmodule Pleroma.Emoji do
end
defp load_from_file_stream(stream) do
+ default_tag =
+ stream.path
+ |> Path.basename(".txt")
+ |> get_default_tag()
+
stream
|> Stream.map(&String.trim/1)
|> Stream.map(fn line ->
case String.split(line, ~r/,\s*/) do
- [name, file] -> {name, file}
- _ -> nil
+ [name, file, tags] ->
+ {name, file, tags}
+
+ [name, file] ->
+ {name, file, default_tag}
+
+ _ ->
+ nil
end
end)
|> Enum.to_list()
end
+ @spec get_default_tag(String.t()) :: String.t()
+ defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do
+ Keyword.get(
+ Application.get_env(:pleroma, :emoji),
+ String.to_existing_atom(file_name <> "_tag")
+ )
+ end
+
+ defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag)
+
defp load_from_globs(globs) do
static_path = Path.join(:code.priv_dir(:pleroma), "static")
paths =
Enum.map(globs, fn glob ->
+ static_part =
+ Path.dirname(glob)
+ |> String.replace_trailing("**", "")
+
Path.join(static_path, glob)
|> Path.wildcard()
+ |> Enum.map(fn path ->
+ custom_folder =
+ path
+ |> Path.relative_to(Path.join(static_path, static_part))
+ |> Path.dirname()
+
+ [path, custom_folder]
+ end)
end)
|> Enum.concat()
- Enum.map(paths, fn path ->
+ Enum.map(paths, fn [path, custom_folder] ->
+ tag =
+ case custom_folder do
+ "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag)
+ tag -> tag
+ end
+
shortcode = Path.basename(path, Path.extname(path))
external_path = Path.join("/", Path.relative_to(path, static_path))
- {shortcode, external_path}
+ {shortcode, external_path, tag}
end)
end
end
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index e3625383b..8ea9dbd38 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -77,9 +77,9 @@ defmodule Pleroma.Formatter do
def emojify(text, nil), do: text
def emojify(text, emoji, strip \\ false) do
- Enum.reduce(emoji, text, fn {emoji, file}, text ->
- emoji = HTML.strip_tags(emoji)
- file = HTML.strip_tags(file)
+ Enum.reduce(emoji, text, fn emoji_data, text ->
+ emoji = HTML.strip_tags(elem(emoji_data, 0))
+ file = HTML.strip_tags(elem(emoji_data, 1))
html =
if not strip do
@@ -101,7 +101,7 @@ defmodule Pleroma.Formatter do
def demojify(text, nil), do: text
def get_emoji(text) when is_binary(text) do
- Enum.filter(Emoji.get_all(), fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end)
+ Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end)
end
def get_emoji(_), do: []
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 25b990677..f910eb1f9 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -167,7 +167,7 @@ defmodule Pleroma.Web.CommonAPI do
object,
"emoji",
(Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"]))
- |> Enum.reduce(%{}, fn {name, file}, acc ->
+ |> Enum.reduce(%{}, fn {name, file, _}, acc ->
Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
end)
) do
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index f596f703b..49f0170cc 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -285,7 +285,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def emoji_from_profile(%{info: _info} = user) do
(Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name))
- |> Enum.map(fn {shortcode, url} ->
+ |> Enum.map(fn {shortcode, url, _} ->
%{
"type" => "Emoji",
"icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"},
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index eee4e7678..583e4007c 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -178,14 +178,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
defp mastodonized_emoji do
Pleroma.Emoji.get_all()
- |> Enum.map(fn {shortcode, relative_url} ->
+ |> Enum.map(fn {shortcode, relative_url, tags} ->
url = to_string(URI.merge(Web.base_url(), relative_url))
%{
"shortcode" => shortcode,
"static_url" => url,
"visible_in_picker" => true,
- "url" => url
+ "url" => url,
+ "tags" => String.split(tags, ",")
}
end)
end
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index faa733fec..e58d9e4cd 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -266,7 +266,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def emoji(conn, _params) do
- json(conn, Enum.into(Emoji.get_all(), %{}))
+ emoji =
+ Emoji.get_all()
+ |> Enum.map(fn {short_code, path, tags} ->
+ %{short_code => %{image_url: path, tags: String.split(tags, ",")}}
+ end)
+
+ json(conn, emoji)
end
def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
diff --git a/test/emoji_test.exs b/test/emoji_test.exs
new file mode 100644
index 000000000..c9c32e20b
--- /dev/null
+++ b/test/emoji_test.exs
@@ -0,0 +1,30 @@
+defmodule Pleroma.EmojiTest do
+ use ExUnit.Case, async: true
+ alias Pleroma.Emoji
+
+ describe "get_all/0" do
+ setup do
+ emoji_list = Emoji.get_all()
+ {:ok, emoji_list: emoji_list}
+ end
+ test "first emoji", %{emoji_list: emoji_list} do
+ [emoji | _others] = emoji_list
+ {code, path, tags} = emoji
+
+ assert tuple_size(emoji) == 3
+ assert is_binary(code)
+ assert is_binary(path)
+ assert is_binary(tags)
+ end
+
+ test "random emoji", %{emoji_list: emoji_list} do
+ emoji = Enum.random(emoji_list)
+ {code, path, tags} = emoji
+
+ assert tuple_size(emoji) == 3
+ assert is_binary(code)
+ assert is_binary(path)
+ assert is_binary(tags)
+ end
+ end
+end
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index fcdf931b7..e67042a5f 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -271,7 +271,8 @@ defmodule Pleroma.FormatterTest do
test "it returns the emoji used in the text" do
text = "I love :moominmamma:"
- assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png"}]
+ tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
+ assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}]
end
test "it returns a nice empty result when no emojis are present" do
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..3b10c4a1a 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2265,4 +2265,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert link_header =~ ~r/max_id=#{notification1.id}/
end
end
+
+ describe "custom emoji" do
+ test "with tags", %{conn: conn} do
+ [emoji | _body] =
+ conn
+ |> get("/api/v1/custom_emojis")
+ |> json_response(200)
+
+ assert Map.has_key?(emoji, "shortcode")
+ assert Map.has_key?(emoji, "static_url")
+ assert Map.has_key?(emoji, "tags")
+ assert is_list(emoji["tags"])
+ assert Map.has_key?(emoji, "url")
+ assert Map.has_key?(emoji, "visible_in_picker")
+ end
+ end
end
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 832fdc096..1063ad28f 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -164,4 +164,25 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end
end
+
+ describe "/api/pleroma/emoji" do
+ test "returns json with custom emoji with tags", %{conn: conn} do
+ [emoji | _body] =
+ conn
+ |> get("/api/pleroma/emoji")
+ |> json_response(200)
+
+ [key] = Map.keys(emoji)
+
+ %{
+ ^key => %{
+ "image_url" => url,
+ "tags" => tags
+ }
+ } = emoji
+
+ assert is_binary(url)
+ assert is_list(tags)
+ end
+ end
end
--
cgit v1.2.3
From 17d3d05a7196140b62dd791af8d7ced8b0ad9fa1 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Mon, 1 Apr 2019 17:54:30 +0700
Subject: code style
little fix
---
lib/pleroma/emoji.ex | 6 +++---
test/emoji_test.exs | 3 ++-
test/formatter_test.exs | 5 ++++-
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index c35aed6ee..ad3170f9a 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -152,7 +152,7 @@ defmodule Pleroma.Emoji do
"woollysocks"
]
defp load_finmoji(true) do
- tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
+ tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag]
Enum.map(@finmoji, fn finmoji ->
{finmoji, "/finmoji/128px/#{finmoji}-128.png", tag}
@@ -193,14 +193,14 @@ defmodule Pleroma.Emoji do
end
@spec get_default_tag(String.t()) :: String.t()
- defp get_default_tag(file_name) when file_name in ["emoji", "custom_emojii"] do
+ defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do
Keyword.get(
Application.get_env(:pleroma, :emoji),
String.to_existing_atom(file_name <> "_tag")
)
end
- defp get_default_tag(_), do: Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag)
+ defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag]
defp load_from_globs(globs) do
static_path = Path.join(:code.priv_dir(:pleroma), "static")
diff --git a/test/emoji_test.exs b/test/emoji_test.exs
index c9c32e20b..a90213d7d 100644
--- a/test/emoji_test.exs
+++ b/test/emoji_test.exs
@@ -7,6 +7,7 @@ defmodule Pleroma.EmojiTest do
emoji_list = Emoji.get_all()
{:ok, emoji_list: emoji_list}
end
+
test "first emoji", %{emoji_list: emoji_list} do
[emoji | _others] = emoji_list
{code, path, tags} = emoji
@@ -19,7 +20,7 @@ defmodule Pleroma.EmojiTest do
test "random emoji", %{emoji_list: emoji_list} do
emoji = Enum.random(emoji_list)
- {code, path, tags} = emoji
+ {code, path, tags} = emoji
assert tuple_size(emoji) == 3
assert is_binary(code)
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index e67042a5f..38430e170 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -272,7 +272,10 @@ defmodule Pleroma.FormatterTest do
text = "I love :moominmamma:"
tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
- assert Formatter.get_emoji(text) == [{"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}]
+
+ assert Formatter.get_emoji(text) == [
+ {"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}
+ ]
end
test "it returns a nice empty result when no emojis are present" do
--
cgit v1.2.3
From 49733f61763091514faa49493fdc20b795c08c1c Mon Sep 17 00:00:00 2001
From: Alex S
Date: Mon, 1 Apr 2019 18:28:19 +0700
Subject: add docs folder to gitignore
ref #770
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.gitignore b/.gitignore
index 04c61ede7..774893b35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,6 @@ erl_crash.dump
# Editor config
/.vscode/
+
+# Prevent committing docs files
+/priv/static/doc/*
--
cgit v1.2.3
From cbe09d94d1e71b2ee5fdce51d3ac014bf69a6b88 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 1 Apr 2019 14:46:50 +0300
Subject: Added `force_login` authentication option (previously applied by
default).
---
lib/pleroma/web/controller_helper.ex | 5 +++++
lib/pleroma/web/oauth/oauth_controller.ex | 37 ++++++++++++++++++++++++-------
lib/pleroma/web/router.ex | 15 ++++++++-----
3 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index 4d6192db0..6fc5a3cb6 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
+ # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+ @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
+ def truthy_param?(nil), do: nil
+ def truthy_param?(value), do: value not in @falsy_param_values
+
def oauth_scopes(params, default) do
# Note: `scopes` is used by Mastodon — supporting it but sticking to
# OAuth's standard `scope` wherever we control it
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index ebb3dd253..0221b4c6f 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Auth.Authenticator
+ alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
@@ -19,7 +20,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do
action_fallback(Pleroma.Web.OAuth.FallbackController)
- def authorize(conn, params) do
+ def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
+ if ControllerHelper.truthy_param?(params["force_login"]) do
+ do_authorize(conn, params)
+ else
+ redirect_uri =
+ if is_binary(params["redirect_uri"]) do
+ params["redirect_uri"]
+ else
+ app = Repo.preload(token, :app).app
+
+ app.redirect_uris
+ |> String.split()
+ |> Enum.at(0)
+ end
+
+ redirect(conn, external: redirect_uri(conn, redirect_uri))
+ end
+ end
+
+ def authorize(conn, params), do: do_authorize(conn, params)
+
+ defp do_authorize(conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
@@ -51,13 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
- redirect_uri =
- if redirect_uri == "." do
- # Special case: Local MastodonFE
- mastodon_api_url(conn, :login)
- else
- redirect_uri
- end
+ redirect_uri = redirect_uri(conn, redirect_uri)
cond do
redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
@@ -221,4 +237,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
nil
end
end
+
+ # Special case: Local MastodonFE
+ defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :index, [])
+
+ defp redirect_uri(_conn, redirect_uri), do: redirect_uri
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 9ccb4e535..8acab304a 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
+ pipeline :oauth do
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ end
+
pipeline :api do
plug(:accepts, ["json"])
plug(:fetch_session)
@@ -105,10 +110,6 @@ defmodule Pleroma.Web.Router do
plug(:accepts, ["json", "xml"])
end
- pipeline :oauth do
- plug(:accepts, ["html", "json"])
- end
-
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
end
@@ -200,7 +201,11 @@ defmodule Pleroma.Web.Router do
end
scope "/oauth", Pleroma.Web.OAuth do
- get("/authorize", OAuthController, :authorize)
+ scope [] do
+ pipe_through(:oauth)
+ get("/authorize", OAuthController, :authorize)
+ end
+
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
--
cgit v1.2.3
From 6910fb371b221a130bebf97c712fdccc26b50c27 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Mon, 1 Apr 2019 17:25:25 +0300
Subject: Fixed local MastoFE authentication / `force_login` option.
---
lib/pleroma/web/controller_helper.ex | 2 +-
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 14 +++++++++++---
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index 6fc5a3cb6..181483664 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Web.ControllerHelper do
# As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
@falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
- def truthy_param?(nil), do: nil
+ def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
def truthy_param?(value), do: value not in @falsy_param_values
def oauth_scopes(params, default) do
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index eee4e7678..457020fe7 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1249,16 +1249,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
"glitch"
end
- def login(conn, %{"code" => code}) do
+ def login(%{assigns: %{user: %User{}}} = conn, _params) do
+ redirect(conn, to: local_mastodon_root_path(conn))
+ end
+
+ @doc "Local Mastodon FE login init action"
+ def login(conn, %{"code" => auth_token}) do
with {:ok, app} <- get_or_make_app(),
- %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id),
+ %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
{:ok, token} <- Token.exchange_token(app, auth) do
conn
|> put_session(:oauth_token, token.token)
- |> redirect(to: "/web/getting-started")
+ |> redirect(to: local_mastodon_root_path(conn))
end
end
+ @doc "Local Mastodon FE callback action"
def login(conn, _) do
with {:ok, app} <- get_or_make_app() do
path =
@@ -1276,6 +1282,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"])
+
defp get_or_make_app do
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
scopes = ["read", "write", "follow", "push"]
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 0221b4c6f..e16d08196 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -239,7 +239,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
# Special case: Local MastodonFE
- defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :index, [])
+ defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
defp redirect_uri(_conn, redirect_uri), do: redirect_uri
end
--
cgit v1.2.3
From 715a31c1ed7ff856bae8ee4dc3536f3cf545f60a Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 18:13:13 +0200
Subject: COPYING: wrap to 79, city.jpg Unsplash, wording
[ci skip]
---
COPYING | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/COPYING b/COPYING
index 2275071a4..82fac8bbc 100644
--- a/COPYING
+++ b/COPYING
@@ -1,8 +1,13 @@
-Unless otherwise stated this repository is copyright © 2017-2019 Pleroma Authors , and is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file in AGPL-3.
+Unless otherwise stated this repository is copyright © 2017-2019
+Pleroma Authors , and is distributed under
+The GNU Affero General Public License Version 3, you should have received a
+copy of the license file in AGPL-3.
---
-The following files are copyright © 2019 shitposter.club, and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file into CC-BY-SA-4.0.
+The following files are copyright © 2019 shitposter.club, and are distributed
+under the Creative Commons Attribution-ShareAlike 4.0 International license,
+you should have received a copy of the license file as CC-BY-SA-4.0.
priv/static/images/pleroma-fox-tan.png
priv/static/images/pleroma-fox-tan-smol.png
@@ -10,13 +15,34 @@ priv/static/images/pleroma-tan.png
---
-The following files are copyright © 2017-2019 Pleroma Authors , and are distributed under the Creative Commons Attribution-ShareAlike 4.0 International license, you should have received a copy of the license file into CC-BY-SA-4.0.
+The following files are copyright © 2017-2019 Pleroma Authors
+ , and are distributed under the Creative Commons
+Attribution-ShareAlike 4.0 International license, you should have received
+a copy of the license file as CC-BY-SA-4.0.
priv/static/images/avi.png
priv/static/images/banner.png
-priv/static/images/city.jpg
priv/static/instance/thumbnail.jpeg
---
-The files present under the priv/static/finmoji directory are copyright Finland , and are distributed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International license, you should have received a copy of the license file into CC-BY-NC-ND-4.0.
+All photos published on Unsplash can be used for free. You can use them for
+commercial and noncommercial purposes. You do not need to ask permission from
+or provide credit to the photographer or Unsplash, although it is appreciated
+when possible.
+
+More precisely, Unsplash grants you an irrevocable, nonexclusive, worldwide
+copyright license to download, copy, modify, distribute, perform, and use
+photos from Unsplash for free, including for commercial purposes, without
+permission from or attributing the photographer or Unsplash. This license
+does not include the right to compile photos from Unsplash to replicate
+a similar or competing service.
+
+priv/static/images/city.jpg
+
+---
+
+The files present under the priv/static/finmoji directory are copyright
+Finland , and are distributed under the Creative
+Commons Attribution-NonCommercial-NoDerivatives 4.0 International license, you
+should have received a copy of the license file as CC-BY-NC-ND-4.0.
--
cgit v1.2.3
From 66e7d4966d851ba25a01a4f371c2f9fec8220103 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 1 Apr 2019 18:34:53 +0200
Subject: COPYING: Wording
[ci skip]
---
COPYING | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/COPYING b/COPYING
index 82fac8bbc..ceec519ae 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
Unless otherwise stated this repository is copyright © 2017-2019
Pleroma Authors , and is distributed under
The GNU Affero General Public License Version 3, you should have received a
-copy of the license file in AGPL-3.
+copy of the license file as AGPL-3.
---
--
cgit v1.2.3
From 1d01e8e656c364b97b9ee36a6173a830d3f5f4fc Mon Sep 17 00:00:00 2001
From: Sachin Joshi
Date: Mon, 1 Apr 2019 22:12:02 +0545
Subject: [OStatus] adds status to pleroma instance if the url given is a
status
---
.../web/twitter_api/controllers/util_controller.ex | 48 ++++++----
test/fixtures/httpoison_mock/emelie.json | 106 +++++++++++++++++++++
test/fixtures/httpoison_mock/status.emelie.json | 64 +++++++++++++
test/support/http_request_mock.ex | 16 ++++
test/web/twitter_api/util_controller_test.exs | 17 ++++
5 files changed, 234 insertions(+), 17 deletions(-)
create mode 100644 test/fixtures/httpoison_mock/emelie.json
create mode 100644 test/fixtures/httpoison_mock/status.emelie.json
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index faa733fec..7f301a518 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
require Logger
alias Comeonin.Pbkdf2
+ alias Pleroma.Activity
alias Pleroma.Emoji
alias Pleroma.Notification
alias Pleroma.PasswordResetToken
@@ -73,26 +74,39 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
- {err, followee} = OStatus.find_or_make_user(acct)
- avatar = User.avatar_url(followee)
- name = followee.nickname
- id = followee.id
-
- if !!user do
- conn
- |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
- else
- conn
- |> render("follow_login.html", %{
- error: false,
- acct: acct,
- avatar: avatar,
- name: name,
- id: id
- })
+ case is_status?(acct) do
+ true ->
+ {:ok, object} = ActivityPub.fetch_object_from_id(acct)
+ %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
+ redirect(conn, to: "/notice/#{activity_id}")
+
+ false ->
+ {err, followee} = OStatus.find_or_make_user(acct)
+ avatar = User.avatar_url(followee)
+ name = followee.nickname
+ id = followee.id
+
+ if !!user do
+ conn
+ |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+ else
+ conn
+ |> render("follow_login.html", %{
+ error: false,
+ acct: acct,
+ avatar: avatar,
+ name: name,
+ id: id
+ })
+ end
end
end
+ defp is_status?(acct) do
+ %URI{path: path} = URI.parse(acct)
+ Regex.match?(~r/\/users\/[^\/]+\/statuses\/([0-9]+)$/, path)
+ end
+
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
diff --git a/test/fixtures/httpoison_mock/emelie.json b/test/fixtures/httpoison_mock/emelie.json
new file mode 100644
index 000000000..2e164ffdf
--- /dev/null
+++ b/test/fixtures/httpoison_mock/emelie.json
@@ -0,0 +1,106 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+ "toot": "http://joinmastodon.org/ns#",
+ "featured": {
+ "@id": "toot:featured",
+ "@type": "@id"
+ },
+ "alsoKnownAs": {
+ "@id": "as:alsoKnownAs",
+ "@type": "@id"
+ },
+ "movedTo": {
+ "@id": "as:movedTo",
+ "@type": "@id"
+ },
+ "schema": "http://schema.org#",
+ "PropertyValue": "schema:PropertyValue",
+ "value": "schema:value",
+ "Hashtag": "as:Hashtag",
+ "Emoji": "toot:Emoji",
+ "IdentityProof": "toot:IdentityProof",
+ "focalPoint": {
+ "@container": "@list",
+ "@id": "toot:focalPoint"
+ }
+ }
+ ],
+ "id": "https://mastodon.social/users/emelie",
+ "type": "Person",
+ "following": "https://mastodon.social/users/emelie/following",
+ "followers": "https://mastodon.social/users/emelie/followers",
+ "inbox": "https://mastodon.social/users/emelie/inbox",
+ "outbox": "https://mastodon.social/users/emelie/outbox",
+ "featured": "https://mastodon.social/users/emelie/collections/featured",
+ "preferredUsername": "emelie",
+ "name": "emelie 🎨",
+ "summary": "23 / #Sweden / #Artist / #Equestrian / #GameDev
If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
",
+ "url": "https://mastodon.social/@emelie",
+ "manuallyApprovesFollowers": false,
+ "publicKey": {
+ "id": "https://mastodon.social/users/emelie#main-key",
+ "owner": "https://mastodon.social/users/emelie",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3CWs1oAJPE3ZJ9sj6Ut\n/Mu+mTE7MOijsQc8/6c73XVVuhIEomiozJIH7l8a7S1n5SYL4UuiwcubSOi7u1bb\nGpYnp5TYhN+Cxvq/P80V4/ncNIPSQzS49it7nSLeG5pA21lGPDA44huquES1un6p\n9gSmbTwngVX9oe4MYuUeh0Z7vijjU13Llz1cRq/ZgPQPgfz+2NJf+VeXnvyDZDYx\nZPVBBlrMl3VoGbu0M5L8SjY35559KCZ3woIvqRolcoHXfgvJMdPcJgSZVYxlCw3d\nA95q9jQcn6s87CPSUs7bmYEQCrDVn5m5NER5TzwBmP4cgJl9AaDVWQtRd4jFZNTx\nlQIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "tag": [
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/explore/sweden",
+ "name": "#sweden"
+ },
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/explore/gamedev",
+ "name": "#gamedev"
+ },
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/explore/artist",
+ "name": "#artist"
+ },
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/explore/equestrian",
+ "name": "#equestrian"
+ }
+ ],
+ "attachment": [
+ {
+ "type": "PropertyValue",
+ "name": "Ko-fi",
+ "value": "https:// ko-fi.com/emeliepng "
+ },
+ {
+ "type": "PropertyValue",
+ "name": "Instagram",
+ "value": "https://www. instagram.com/emelie_png/ "
+ },
+ {
+ "type": "PropertyValue",
+ "name": "Carrd",
+ "value": "https:// emelie.carrd.co/ "
+ },
+ {
+ "type": "PropertyValue",
+ "name": "Artstation",
+ "value": "https:// emiri.artstation.com "
+ }
+ ],
+ "endpoints": {
+ "sharedInbox": "https://mastodon.social/inbox"
+ },
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "url": "https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png"
+ },
+ "image": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "url": "https://files.mastodon.social/accounts/headers/000/015/657/original/847f331f3dd9e38b.png"
+ }
+}
diff --git a/test/fixtures/httpoison_mock/status.emelie.json b/test/fixtures/httpoison_mock/status.emelie.json
new file mode 100644
index 000000000..4aada0377
--- /dev/null
+++ b/test/fixtures/httpoison_mock/status.emelie.json
@@ -0,0 +1,64 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "sensitive": "as:sensitive",
+ "Hashtag": "as:Hashtag",
+ "toot": "http://joinmastodon.org/ns#",
+ "Emoji": "toot:Emoji",
+ "focalPoint": {
+ "@container": "@list",
+ "@id": "toot:focalPoint"
+ }
+ }
+ ],
+ "id": "https://mastodon.social/users/emelie/statuses/101849165031453009",
+ "type": "Note",
+ "summary": null,
+ "inReplyTo": null,
+ "published": "2019-04-01T05:02:05Z",
+ "url": "https://mastodon.social/@emelie/101849165031453009",
+ "attributedTo": "https://mastodon.social/users/emelie",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://mastodon.social/users/emelie/followers"
+ ],
+ "sensitive": false,
+ "atomUri": "https://mastodon.social/users/emelie/statuses/101849165031453009",
+ "inReplyToAtomUri": null,
+ "conversation": "tag:mastodon.social,2019-04-01:objectId=94350309:objectType=Conversation",
+ "content": "You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 #mastocats
",
+ "contentMap": {
+ "en": "You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 #mastocats
"
+ },
+ "attachment": [
+ {
+ "type": "Document",
+ "mediaType": "video/mp4",
+ "url": "https://files.mastodon.social/media_attachments/files/013/049/816/original/e7831178a5e0d6d4.mp4",
+ "name": null
+ }
+ ],
+ "tag": [
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/tags/mastocats",
+ "name": "#mastocats"
+ }
+ ],
+ "replies": {
+ "id": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies",
+ "type": "Collection",
+ "first": {
+ "type": "CollectionPage",
+ "partOf": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies",
+ "items": []
+ }
+ }
+}
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index 78e8efc9d..2148bd4e7 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -36,6 +36,22 @@ defmodule HttpRequestMock do
}}
end
+ def get("https://mastodon.social/users/emelie/statuses/101849165031453009", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/status.emelie.json")
+ }}
+ end
+
+ def get("https://mastodon.social/users/emelie", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/emelie.json")
+ }}
+ end
+
def get(
"https://osada.macgirvin.com/.well-known/webfinger?resource=acct:mike@osada.macgirvin.com",
_,
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 832fdc096..f4a3ce501 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -6,6 +6,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ setup do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
describe "POST /api/pleroma/follow_import" do
test "it returns HTTP 200", %{conn: conn} do
user1 = insert(:user)
@@ -164,4 +169,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end
end
+
+ describe "GET /ostatus_subscribe?acct=...." do
+ test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
+ conn =
+ get(
+ conn,
+ "/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009"
+ )
+
+ assert redirected_to(conn) =~ "/notice/"
+ end
+ end
end
--
cgit v1.2.3
From b6f9f7b8aa659c10049b8c43326e58a4b1b18664 Mon Sep 17 00:00:00 2001
From: Sergey Suprunenko
Date: Mon, 1 Apr 2019 22:40:48 +0200
Subject: Handle dates in the Unix timestamp format (Fixes #763)
---
lib/pleroma/web/common_api/utils.ex | 17 +++++++++++-
test/web/common_api/common_api_utils_test.exs | 37 +++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index f596f703b..3f5348d66 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -240,8 +240,23 @@ defmodule Pleroma.Web.CommonAPI.Utils do
Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y")
end
+ def date_to_asctime(date) when is_float(date) do
+ date
+ |> trunc()
+ |> date_to_asctime()
+ end
+
+ def date_to_asctime(date) when is_integer(date) do
+ with {:ok, date} <- DateTime.from_unix(date) do
+ format_asctime(date)
+ else
+ _e ->
+ ""
+ end
+ end
+
def date_to_asctime(date) do
- with {:ok, date, _offset} <- date |> DateTime.from_iso8601() do
+ with {:ok, date, _offset} <- DateTime.from_iso8601(date) do
format_asctime(date)
else
_e ->
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index e04b9f9b5..0f8b28d9c 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -153,4 +153,41 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
assert conversation_id == object.id
end
end
+
+ describe "formats date to asctime" do
+ test "when date is an integer Unix timestamp" do
+ date = DateTime.utc_now() |> DateTime.to_unix()
+
+ expected =
+ date
+ |> DateTime.from_unix!()
+ |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+
+ test "when date is a float Unix timestamp" do
+ date = 1_553_808_404.602961
+
+ expected =
+ date
+ |> trunc()
+ |> DateTime.from_unix!()
+ |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+
+ test "when date is in ISO 8601 format" do
+ date = DateTime.utc_now() |> DateTime.to_iso8601()
+
+ expected =
+ date
+ |> DateTime.from_iso8601()
+ |> elem(1)
+ |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+ end
end
--
cgit v1.2.3
From 6386c1c9c1ff971c784744922a479ae38e5fdbad Mon Sep 17 00:00:00 2001
From: Sachin Joshi
Date: Tue, 2 Apr 2019 10:26:09 +0545
Subject: fetch url for OStatus to know if it is a/c or status
---
.../web/twitter_api/controllers/util_controller.ex | 6 +-
test/fixtures/httpoison_mock/emelie.atom | 306 +++++++++++++++++++++
test/fixtures/httpoison_mock/emelie.json | 106 -------
test/fixtures/httpoison_mock/webfinger_emelie.json | 36 +++
test/support/http_request_mock.ex | 21 ++
test/web/twitter_api/util_controller_test.exs | 10 +
6 files changed, 377 insertions(+), 108 deletions(-)
create mode 100644 test/fixtures/httpoison_mock/emelie.atom
delete mode 100644 test/fixtures/httpoison_mock/emelie.json
create mode 100644 test/fixtures/httpoison_mock/webfinger_emelie.json
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 7f301a518..2a1c73111 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -103,8 +103,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
defp is_status?(acct) do
- %URI{path: path} = URI.parse(acct)
- Regex.match?(~r/\/users\/[^\/]+\/statuses\/([0-9]+)$/, path)
+ case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do
+ {:ok, %{"type" => "Note"}} -> true
+ _ -> false
+ end
end
def do_remote_follow(conn, %{
diff --git a/test/fixtures/httpoison_mock/emelie.atom b/test/fixtures/httpoison_mock/emelie.atom
new file mode 100644
index 000000000..ddaa1c6ca
--- /dev/null
+++ b/test/fixtures/httpoison_mock/emelie.atom
@@ -0,0 +1,306 @@
+
+
+ https://mastodon.social/users/emelie.atom
+ emelie 🎨
+ 23 / #Sweden / #Artist / #Equestrian / #GameDev
+
+If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
+ 2019-02-04T20:22:19Z
+ https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png
+
+ https://mastodon.social/users/emelie
+ http://activitystrea.ms/schema/1.0/person
+ https://mastodon.social/users/emelie
+ emelie
+ emelie@mastodon.social
+ <p>23 / <a href="https://mastodon.social/tags/sweden" class="mention hashtag" rel="tag">#<span>Sweden</span></a> / <a href="https://mastodon.social/tags/artist" class="mention hashtag" rel="tag">#<span>Artist</span></a> / <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>Equestrian</span></a> / <a href="https://mastodon.social/tags/gamedev" class="mention hashtag" rel="tag">#<span>GameDev</span></a></p><p>If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</p>
+
+
+
+ emelie
+ emelie 🎨
+ 23 / #Sweden / #Artist / #Equestrian / #GameDev
+
+If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101850331907006641
+ 2019-04-01T09:58:50Z
+ 2019-04-01T09:58:50Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Me: I'm going to make this vital change to my world building in the morning, no way I'll forget this, it's too big of a deal<br />Also me: forgets</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849626603073336
+ 2019-04-01T06:59:28Z
+ 2019-04-01T06:59:28Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p><span class="h-card"><a href="https://mastodon.social/@Fergant" class="u-url mention">@<span>Fergant</span></a></span> Dom är i stort sett religiös skrift vid det här laget 👏👏</p><p>har dock bara läst svenska översättningen, kanske är dags att jag läser dom på engelska</p>
+
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849580030237068
+ 2019-04-01T06:47:37Z
+ 2019-04-01T06:47:37Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>What's you people's favourite fantasy books? Give me some hot tips 🌞</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849550599949363
+ 2019-04-01T06:40:08Z
+ 2019-04-01T06:40:08Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Stick them legs out 💃 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849191533152720
+ 2019-04-01T05:08:49Z
+ 2019-04-01T05:08:49Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>long 🐱 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849165031453009
+ 2019-04-01T05:02:05Z
+ 2019-04-01T05:02:05Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101846512530748693
+ 2019-03-31T17:47:31Z
+ 2019-03-31T17:47:31Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Hello look at this boy having a decent haircut for once <a href="https://mastodon.social/tags/mastohorses" class="mention hashtag" rel="tag">#<span>mastohorses</span></a> <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>equestrian</span></a></p>
+
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101846181093805500
+ 2019-03-31T16:23:14Z
+ 2019-03-31T16:23:14Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Sorry did I disturb the who-is-the-longest-cat competition ? <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101845897513133849
+ 2019-03-31T15:11:07Z
+ 2019-03-31T15:11:07Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ more earthsea ramblings
+ <p>I'm re-watching Tales from Earthsea for the first time since I read the books, and that Therru doesn't squash Cob like a spider, as Orm Embar did is a wasted opportunity tbh</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101841219051533307
+ 2019-03-30T19:21:19Z
+ 2019-03-30T19:21:19Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>I gave my cats some mackerel and they ate it all in 0.3 seconds, and now they won't stop meowing for more, and I'm tired plz shut up</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101839949762341381
+ 2019-03-30T13:58:31Z
+ 2019-03-30T13:58:31Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>yet I'm confused about this american dude with a gun, like the heck r ya doin in mah ghibli</p>
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101839928677863590
+ 2019-03-30T13:53:09Z
+ 2019-03-30T13:53:09Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>2 hours into Ni no Kuni 2 and I've already sold my soul to this game</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101836329521599438
+ 2019-03-29T22:37:51Z
+ 2019-03-29T22:37:51Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Pippi Longstocking the original one-punch /man</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835905282948341
+ 2019-03-29T20:49:57Z
+ 2019-03-29T20:49:57Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>I've had so much wine I thought I had a 3rd brother</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835878059204660
+ 2019-03-29T20:43:02Z
+ 2019-03-29T20:43:02Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>ååååhhh booi</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835848050598939
+ 2019-03-29T20:35:24Z
+ 2019-03-29T20:35:24Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p><span class="h-card"><a href="https://thraeryn.net/@thraeryn" class="u-url mention">@<span>thraeryn</span></a></span> if I spent 1 hour and a half watching this monstrosity, I need to</p>
+
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835823138262290
+ 2019-03-29T20:29:04Z
+ 2019-03-29T20:29:04Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ medical, fluids mention
+ <p><span class="h-card"><a href="https://icosahedron.website/@Trev" class="u-url mention">@<span>Trev</span></a></span> *hugs* ✨</p>
+
+
+ public
+
+
+
+
+
+
diff --git a/test/fixtures/httpoison_mock/emelie.json b/test/fixtures/httpoison_mock/emelie.json
deleted file mode 100644
index 2e164ffdf..000000000
--- a/test/fixtures/httpoison_mock/emelie.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- "https://w3id.org/security/v1",
- {
- "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
- "toot": "http://joinmastodon.org/ns#",
- "featured": {
- "@id": "toot:featured",
- "@type": "@id"
- },
- "alsoKnownAs": {
- "@id": "as:alsoKnownAs",
- "@type": "@id"
- },
- "movedTo": {
- "@id": "as:movedTo",
- "@type": "@id"
- },
- "schema": "http://schema.org#",
- "PropertyValue": "schema:PropertyValue",
- "value": "schema:value",
- "Hashtag": "as:Hashtag",
- "Emoji": "toot:Emoji",
- "IdentityProof": "toot:IdentityProof",
- "focalPoint": {
- "@container": "@list",
- "@id": "toot:focalPoint"
- }
- }
- ],
- "id": "https://mastodon.social/users/emelie",
- "type": "Person",
- "following": "https://mastodon.social/users/emelie/following",
- "followers": "https://mastodon.social/users/emelie/followers",
- "inbox": "https://mastodon.social/users/emelie/inbox",
- "outbox": "https://mastodon.social/users/emelie/outbox",
- "featured": "https://mastodon.social/users/emelie/collections/featured",
- "preferredUsername": "emelie",
- "name": "emelie 🎨",
- "summary": "23 / #Sweden / #Artist / #Equestrian / #GameDev
If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
",
- "url": "https://mastodon.social/@emelie",
- "manuallyApprovesFollowers": false,
- "publicKey": {
- "id": "https://mastodon.social/users/emelie#main-key",
- "owner": "https://mastodon.social/users/emelie",
- "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3CWs1oAJPE3ZJ9sj6Ut\n/Mu+mTE7MOijsQc8/6c73XVVuhIEomiozJIH7l8a7S1n5SYL4UuiwcubSOi7u1bb\nGpYnp5TYhN+Cxvq/P80V4/ncNIPSQzS49it7nSLeG5pA21lGPDA44huquES1un6p\n9gSmbTwngVX9oe4MYuUeh0Z7vijjU13Llz1cRq/ZgPQPgfz+2NJf+VeXnvyDZDYx\nZPVBBlrMl3VoGbu0M5L8SjY35559KCZ3woIvqRolcoHXfgvJMdPcJgSZVYxlCw3d\nA95q9jQcn6s87CPSUs7bmYEQCrDVn5m5NER5TzwBmP4cgJl9AaDVWQtRd4jFZNTx\nlQIDAQAB\n-----END PUBLIC KEY-----\n"
- },
- "tag": [
- {
- "type": "Hashtag",
- "href": "https://mastodon.social/explore/sweden",
- "name": "#sweden"
- },
- {
- "type": "Hashtag",
- "href": "https://mastodon.social/explore/gamedev",
- "name": "#gamedev"
- },
- {
- "type": "Hashtag",
- "href": "https://mastodon.social/explore/artist",
- "name": "#artist"
- },
- {
- "type": "Hashtag",
- "href": "https://mastodon.social/explore/equestrian",
- "name": "#equestrian"
- }
- ],
- "attachment": [
- {
- "type": "PropertyValue",
- "name": "Ko-fi",
- "value": "https:// ko-fi.com/emeliepng "
- },
- {
- "type": "PropertyValue",
- "name": "Instagram",
- "value": "https://www. instagram.com/emelie_png/ "
- },
- {
- "type": "PropertyValue",
- "name": "Carrd",
- "value": "https:// emelie.carrd.co/ "
- },
- {
- "type": "PropertyValue",
- "name": "Artstation",
- "value": "https:// emiri.artstation.com "
- }
- ],
- "endpoints": {
- "sharedInbox": "https://mastodon.social/inbox"
- },
- "icon": {
- "type": "Image",
- "mediaType": "image/png",
- "url": "https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png"
- },
- "image": {
- "type": "Image",
- "mediaType": "image/png",
- "url": "https://files.mastodon.social/accounts/headers/000/015/657/original/847f331f3dd9e38b.png"
- }
-}
diff --git a/test/fixtures/httpoison_mock/webfinger_emelie.json b/test/fixtures/httpoison_mock/webfinger_emelie.json
new file mode 100644
index 000000000..0b61cb618
--- /dev/null
+++ b/test/fixtures/httpoison_mock/webfinger_emelie.json
@@ -0,0 +1,36 @@
+{
+ "aliases": [
+ "https://mastodon.social/@emelie",
+ "https://mastodon.social/users/emelie"
+ ],
+ "links": [
+ {
+ "href": "https://mastodon.social/@emelie",
+ "rel": "http://webfinger.net/rel/profile-page",
+ "type": "text/html"
+ },
+ {
+ "href": "https://mastodon.social/users/emelie.atom",
+ "rel": "http://schemas.google.com/g/2010#updates-from",
+ "type": "application/atom+xml"
+ },
+ {
+ "href": "https://mastodon.social/users/emelie",
+ "rel": "self",
+ "type": "application/activity+json"
+ },
+ {
+ "href": "https://mastodon.social/api/salmon/15657",
+ "rel": "salmon"
+ },
+ {
+ "href": "data:application/magic-public-key,RSA.u3CWs1oAJPE3ZJ9sj6Ut_Mu-mTE7MOijsQc8_6c73XVVuhIEomiozJIH7l8a7S1n5SYL4UuiwcubSOi7u1bbGpYnp5TYhN-Cxvq_P80V4_ncNIPSQzS49it7nSLeG5pA21lGPDA44huquES1un6p9gSmbTwngVX9oe4MYuUeh0Z7vijjU13Llz1cRq_ZgPQPgfz-2NJf-VeXnvyDZDYxZPVBBlrMl3VoGbu0M5L8SjY35559KCZ3woIvqRolcoHXfgvJMdPcJgSZVYxlCw3dA95q9jQcn6s87CPSUs7bmYEQCrDVn5m5NER5TzwBmP4cgJl9AaDVWQtRd4jFZNTxlQ==.AQAB",
+ "rel": "magic-public-key"
+ },
+ {
+ "rel": "http://ostatus.org/schema/1.0/subscribe",
+ "template": "https://mastodon.social/authorize_interaction?uri={uri}"
+ }
+ ],
+ "subject": "acct:emelie@mastodon.social"
+}
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index 2148bd4e7..d3b547d91 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -52,6 +52,27 @@ defmodule HttpRequestMock do
}}
end
+ def get(
+ "https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/emelie",
+ _,
+ _,
+ _
+ ) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/webfinger_emelie.json")
+ }}
+ end
+
+ def get("https://mastodon.social/users/emelie.atom", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/emelie.atom")
+ }}
+ end
+
def get(
"https://osada.macgirvin.com/.well-known/webfinger?resource=acct:mike@osada.macgirvin.com",
_,
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index f4a3ce501..e4dd97d46 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -180,5 +180,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
assert redirected_to(conn) =~ "/notice/"
end
+
+ test "show follow account page if the `acct` is a account link", %{conn: conn} do
+ response =
+ get(
+ conn,
+ "/ostatus_subscribe?acct=https://mastodon.social/users/emelie"
+ )
+
+ assert html_response(response, 200) =~ "Log in to follow"
+ end
end
end
--
cgit v1.2.3
From 4861558b93e9ff063cd32b1cae30ec37d8d53211 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 08:58:09 +0300
Subject: Separate CI jobs to 3 stages to allow them to be executed in parallel
---
.gitlab-ci.yml | 61 +++++++++++++++++++++++++++++-----------------------------
1 file changed, 30 insertions(+), 31 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dbdf59f65..9d95ff7af 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,5 @@
image: elixir:1.8.1
-services:
- - name: postgres:9.6.2
- command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
variables:
POSTGRES_DB: pleroma_test
@@ -17,56 +14,58 @@ cache:
- deps
- _build
stages:
- - lint
+ - build
- test
- - analysis
- - docs_build
- - docs_deploy
+ - deploy
before_script:
- mix local.hex --force
- mix local.rebar --force
- - mix deps.get
- - mix compile --force
- - mix ecto.create
- - mix ecto.migrate
-
-lint:
- stage: lint
- script:
- - mix format --check-formatted
-unit-testing:
- stage: test
+build:
+ stage: build
script:
- - mix test --trace --preload-modules
-
-analysis:
- stage: analysis
- script:
- - mix credo --strict --only=warnings,todo,fixme,consistency,readability
+ - mix deps.get --only test
+ - mix compile --force
docs_build:
- stage: docs_build
- services:
+ stage: build
only:
- master@pleroma/pleroma
- develop@pleroma/pleroma
variables:
MIX_ENV: dev
- before_script:
- - mix local.hex --force
- - mix local.rebar --force
+ script:
- mix deps.get
- mix compile
- script:
- mix docs
artifacts:
paths:
- priv/static/doc
+unit-testing:
+ stage: test
+ services:
+ - name: postgres:9.6.2
+ command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
+ script:
+ - mix ecto.create
+ - mix ecto.migrate
+ - mix test --trace --preload-modules
+
+lint:
+ stage: test
+ script:
+ - mix format --check-formatted
+
+analysis:
+ stage: test
+ script:
+ - mix credo --strict --only=warnings,todo,fixme,consistency,readability
+
+
docs_deploy:
- stage: docs_deploy
+ stage: deploy
image: alpine:3.9
services:
only:
--
cgit v1.2.3
From 7827b929fc9816f556dc352c572f6c2ed1f1e470 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 09:02:21 +0300
Subject: huh
---
.gitlab-ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9d95ff7af..9f3e8568f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,7 +25,7 @@ before_script:
build:
stage: build
script:
- - mix deps.get --only test
+ - mix deps.get
- mix compile --force
docs_build:
--
cgit v1.2.3
From 5ee54d81837f7e59e942f524259f361c438dfba4 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 09:07:58 +0300
Subject: what the fuck
---
.gitlab-ci.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9f3e8568f..70fe82ee0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,6 +61,7 @@ lint:
analysis:
stage: test
script:
+ - mix deps.get
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
--
cgit v1.2.3
From 8c71ea5a1a1d4b4e75debb23b801535e19353413 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 09:13:34 +0300
Subject: remove reduntant services in docs deploy and change job names to
kebab case
---
.gitlab-ci.yml | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 70fe82ee0..c07f1a5d3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,5 @@
image: elixir:1.8.1
-
variables:
POSTGRES_DB: pleroma_test
POSTGRES_USER: postgres
@@ -28,7 +27,7 @@ build:
- mix deps.get
- mix compile --force
-docs_build:
+docs-build:
stage: build
only:
- master@pleroma/pleroma
@@ -65,10 +64,9 @@ analysis:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
-docs_deploy:
+docs-deploy:
stage: deploy
image: alpine:3.9
- services:
only:
- master@pleroma/pleroma
- develop@pleroma/pleroma
--
cgit v1.2.3
From f20e8d28de97e154ec43120cb4fc07e2792e955a Mon Sep 17 00:00:00 2001
From: Sachin Joshi
Date: Tue, 2 Apr 2019 12:15:41 +0545
Subject: add support for all status type (ostatus) and replase case with if
---
.../web/twitter_api/controllers/util_controller.ex | 55 +++++++++++-----------
1 file changed, 28 insertions(+), 27 deletions(-)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 2a1c73111..b661c4363 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -74,38 +74,39 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
- case is_status?(acct) do
- true ->
- {:ok, object} = ActivityPub.fetch_object_from_id(acct)
- %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
- redirect(conn, to: "/notice/#{activity_id}")
-
- false ->
- {err, followee} = OStatus.find_or_make_user(acct)
- avatar = User.avatar_url(followee)
- name = followee.nickname
- id = followee.id
-
- if !!user do
- conn
- |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
- else
- conn
- |> render("follow_login.html", %{
- error: false,
- acct: acct,
- avatar: avatar,
- name: name,
- id: id
- })
- end
+ if is_status?(acct) do
+ {:ok, object} = ActivityPub.fetch_object_from_id(acct)
+ %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)
+ avatar = User.avatar_url(followee)
+ name = followee.nickname
+ id = followee.id
+
+ if !!user do
+ conn
+ |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+ else
+ conn
+ |> render("follow_login.html", %{
+ error: false,
+ acct: acct,
+ avatar: avatar,
+ name: name,
+ id: id
+ })
+ end
end
end
defp is_status?(acct) do
case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do
- {:ok, %{"type" => "Note"}} -> true
- _ -> false
+ {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
+ true
+
+ _ ->
+ false
end
end
--
cgit v1.2.3
From 9b2188da7cab43a162d441294db7d3155e2eeab3 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 15:44:56 +0700
Subject: refactoring of emoji tags config to use groups
---
config/config.exs | 9 ++---
lib/pleroma/emoji.ex | 92 ++++++++++++++++++++++++++++------------------------
test/emoji_test.exs | 75 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+), 47 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 245c7d268..4a22167b2 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -56,10 +56,11 @@ config :pleroma, Pleroma.Uploaders.MDII,
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
- custom_tag: "Custom",
- finmoji_tag: "Finmoji",
- emoji_tag: "Emoji",
- custom_emoji_tag: "Custom"
+ groups: [
+ # Place here groups, which have more priority on defaults. Example in `docs/config/custom_emoji.md`
+ Finmoji: "/finmoji/128px/*-128.png",
+ Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
+ ]
config :pleroma, :uri_schemes,
valid_schemes: [
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index ad3170f9a..b60d19e89 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -13,8 +13,14 @@ defmodule Pleroma.Emoji do
This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime.
"""
use GenServer
+
+ @type pattern :: Regex.t() | module() | String.t()
+ @type patterns :: pattern | [pattern]
+ @type group_patterns :: keyword(patterns)
+
@ets __MODULE__.Ets
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
+ @groups Application.get_env(:pleroma, :emoji)[:groups]
@doc false
def start_link do
@@ -73,13 +79,14 @@ defmodule Pleroma.Emoji do
end
defp load do
+ finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)
+ shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, [])
+
emojis =
- (load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++
+ (load_finmoji(finmoji_enabled) ++
load_from_file("config/emoji.txt") ++
load_from_file("config/custom_emoji.txt") ++
- load_from_globs(
- Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, [])
- ))
+ load_from_globs(shortcode_globs))
|> Enum.reject(fn value -> value == nil end)
true = :ets.insert(@ets, emojis)
@@ -151,11 +158,12 @@ defmodule Pleroma.Emoji do
"white_nights",
"woollysocks"
]
- defp load_finmoji(true) do
- tag = Application.get_env(:pleroma, :emoji)[:finmoji_tag]
+ defp load_finmoji(true) do
Enum.map(@finmoji, fn finmoji ->
- {finmoji, "/finmoji/128px/#{finmoji}-128.png", tag}
+ file_name = "/finmoji/128px/#{finmoji}-128.png"
+ group = match_extra(@groups, file_name)
+ {finmoji, file_name, to_string(group)}
end)
end
@@ -170,11 +178,6 @@ defmodule Pleroma.Emoji do
end
defp load_from_file_stream(stream) do
- default_tag =
- stream.path
- |> Path.basename(".txt")
- |> get_default_tag()
-
stream
|> Stream.map(&String.trim/1)
|> Stream.map(fn line ->
@@ -183,7 +186,7 @@ defmodule Pleroma.Emoji do
{name, file, tags}
[name, file] ->
- {name, file, default_tag}
+ {name, file, to_string(match_extra(@groups, file))}
_ ->
nil
@@ -192,48 +195,51 @@ defmodule Pleroma.Emoji do
|> Enum.to_list()
end
- @spec get_default_tag(String.t()) :: String.t()
- defp get_default_tag(file_name) when file_name in ["emoji", "custom_emoji"] do
- Keyword.get(
- Application.get_env(:pleroma, :emoji),
- String.to_existing_atom(file_name <> "_tag")
- )
- end
-
- defp get_default_tag(_), do: Application.get_env(:pleroma, :emoji)[:custom_tag]
-
defp load_from_globs(globs) do
static_path = Path.join(:code.priv_dir(:pleroma), "static")
paths =
Enum.map(globs, fn glob ->
- static_part =
- Path.dirname(glob)
- |> String.replace_trailing("**", "")
-
Path.join(static_path, glob)
|> Path.wildcard()
- |> Enum.map(fn path ->
- custom_folder =
- path
- |> Path.relative_to(Path.join(static_path, static_part))
- |> Path.dirname()
-
- [path, custom_folder]
- end)
end)
|> Enum.concat()
- Enum.map(paths, fn [path, custom_folder] ->
- tag =
- case custom_folder do
- "." -> Keyword.get(Application.get_env(:pleroma, :emoji), :custom_tag)
- tag -> tag
- end
-
+ Enum.map(paths, fn path ->
+ tag = match_extra(@groups, Path.join("/", Path.relative_to(path, static_path)))
shortcode = Path.basename(path, Path.extname(path))
external_path = Path.join("/", Path.relative_to(path, static_path))
- {shortcode, external_path, tag}
+ {shortcode, external_path, to_string(tag)}
+ end)
+ end
+
+ @doc """
+ Finds a matching group for the given extra filename
+ """
+ @spec match_extra(group_patterns(), String.t()) :: atom() | nil
+ def match_extra(group_patterns, filename) do
+ match_group_patterns(group_patterns, fn pattern ->
+ case pattern do
+ %Regex{} = regex -> Regex.match?(regex, filename)
+ string when is_binary(string) -> filename == string
+ end
+ end)
+ end
+
+ defp match_group_patterns(group_patterns, matcher) do
+ Enum.find_value(group_patterns, fn {group, patterns} ->
+ patterns =
+ patterns
+ |> List.wrap()
+ |> Enum.map(fn pattern ->
+ if String.contains?(pattern, "*") do
+ ~r(#{String.replace(pattern, "*", ".*")})
+ else
+ pattern
+ end
+ end)
+
+ Enum.any?(patterns, matcher) && group
end)
end
end
diff --git a/test/emoji_test.exs b/test/emoji_test.exs
index a90213d7d..cb1d62d00 100644
--- a/test/emoji_test.exs
+++ b/test/emoji_test.exs
@@ -28,4 +28,79 @@ defmodule Pleroma.EmojiTest do
assert is_binary(tags)
end
end
+
+ describe "match_extra/2" do
+ setup do
+ groups = [
+ "list of files": ["/emoji/custom/first_file.png", "/emoji/custom/second_file.png"],
+ "wildcard folder": "/emoji/custom/*/file.png",
+ "wildcard files": "/emoji/custom/folder/*.png",
+ "special file": "/emoji/custom/special.png"
+ ]
+
+ {:ok, groups: groups}
+ end
+
+ test "config for list of files", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/first_file.png")
+ |> to_string()
+
+ assert group == "list of files"
+ end
+
+ test "config with wildcard folder", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/some_folder/file.png")
+ |> to_string()
+
+ assert group == "wildcard folder"
+ end
+
+ test "config with wildcard folder and subfolders", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/some_folder/another_folder/file.png")
+ |> to_string()
+
+ assert group == "wildcard folder"
+ end
+
+ test "config with wildcard files", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/folder/some_file.png")
+ |> to_string()
+
+ assert group == "wildcard files"
+ end
+
+ test "config with wildcard files and subfolders", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/folder/another_folder/some_file.png")
+ |> to_string()
+
+ assert group == "wildcard files"
+ end
+
+ test "config for special file", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/custom/special.png")
+ |> to_string()
+
+ assert group == "special file"
+ end
+
+ test "no mathing returns nil", %{groups: groups} do
+ group =
+ groups
+ |> Emoji.match_extra("/emoji/some_undefined.png")
+
+ refute group
+ end
+ end
end
--
cgit v1.2.3
From 851c5bf0936fbc58bf509f79531e6cdc070efde5 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 15:57:57 +0700
Subject: updating custom_emoji docs
---
docs/config/custom_emoji.md | 39 +++++++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md
index e47a75c8e..d37220a72 100644
--- a/docs/config/custom_emoji.md
+++ b/docs/config/custom_emoji.md
@@ -18,21 +18,36 @@ foo, /emoji/custom/foo.png
The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon.
-# Emoji tags
-
-Changing default tags:
-
-* For `Finmoji`, `emoji.txt` and `custom_emoji.txt` are added default tags, which can be configured in the `config.exs`:
-* For emoji loaded from globs:
- - `priv/static/emoji/custom/*.png` - `custom_tag`, can be configured in `config.exs`
- - `priv/static/emoji/custom/TagName/*.png` - folder (`TagName`) is used as tag
+# Emoji tags (groups)
+Default tags are set in `config.exs`.
+```
+config :pleroma, :emoji,
+ shortcode_globs: ["/emoji/custom/**/*.png"],
+ groups: [
+ Finmoji: "/finmoji/128px/*-128.png",
+ Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
+ ]
+```
+Order of the `groups` matters, so to override default tags just put your group on the top of the list. E.g:
```
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
- custom_tag: "Custom", # Default tag for emoji in `priv/static/emoji/custom` path
- finmoji_tag: "Finmoji", # Default tag for Finmoji
- emoji_tag: "Emoji", # Default tag for emoji.txt
- custom_emoji_tag: "Custom" # Default tag for custom_emoji.txt
+ groups: [
+ "Finmoji special": "/finmoji/128px/a_trusted_friend-128.png", # special file
+ "Cirno": "/emoji/custom/cirno*.png", # png files in /emoji/custom/ which start with `cirno`
+ "Special group": "/emoji/custom/special_folder/*.png", # png files in /emoji/custom/special_folder/
+ "Another group": "/emoji/custom/special_folder/*/.png", # png files in /emoji/custom/special_folder/ subfolders
+ Finmoji: "/finmoji/128px/*-128.png",
+ Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
+ ]
```
+
+Priority of tag assign in emoji.txt and custom.txt:
+
+`tag in file > special group setting in config.exs > default setting in config.exs`
+
+Priority for globs:
+
+`special group setting in config.exs > default setting in config.exs`
--
cgit v1.2.3
From 08d64b977f74abb7cb42bf985116eba91d9a6166 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 16:13:34 +0700
Subject: little changes and typos
---
config/config.exs | 2 +-
docs/config/custom_emoji.md | 4 ++--
lib/pleroma/emoji.ex | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 4a22167b2..139ec0ace 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -57,7 +57,7 @@ config :pleroma, Pleroma.Uploaders.MDII,
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
groups: [
- # Place here groups, which have more priority on defaults. Example in `docs/config/custom_emoji.md`
+ # Put groups that have higher priority than defaults here. Example in `docs/config/custom_emoji.md`
Finmoji: "/finmoji/128px/*-128.png",
Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
]
diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md
index d37220a72..49a451fcc 100644
--- a/docs/config/custom_emoji.md
+++ b/docs/config/custom_emoji.md
@@ -30,7 +30,7 @@ config :pleroma, :emoji,
]
```
-Order of the `groups` matters, so to override default tags just put your group on the top of the list. E.g:
+Order of the `groups` matters, so to override default tags just put your group on top of the list. E.g:
```
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
@@ -44,7 +44,7 @@ config :pleroma, :emoji,
]
```
-Priority of tag assign in emoji.txt and custom.txt:
+Priority of tags assigns in emoji.txt and custom.txt:
`tag in file > special group setting in config.exs > default setting in config.exs`
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index b60d19e89..7a60f3961 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -15,8 +15,8 @@ defmodule Pleroma.Emoji do
use GenServer
@type pattern :: Regex.t() | module() | String.t()
- @type patterns :: pattern | [pattern]
- @type group_patterns :: keyword(patterns)
+ @type patterns :: pattern() | [pattern()]
+ @type group_patterns :: keyword(patterns())
@ets __MODULE__.Ets
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
@@ -80,7 +80,7 @@ defmodule Pleroma.Emoji do
defp load do
finmoji_enabled = Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)
- shortcode_globs = Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, [])
+ shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || []
emojis =
(load_finmoji(finmoji_enabled) ++
--
cgit v1.2.3
From 484162c18774ff28842a517ae0afcaaf824e12bf Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 16:26:40 +0700
Subject: test fix
---
test/formatter_test.exs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index 38430e170..e74985c4e 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -271,10 +271,8 @@ defmodule Pleroma.FormatterTest do
test "it returns the emoji used in the text" do
text = "I love :moominmamma:"
- tag = Keyword.get(Application.get_env(:pleroma, :emoji), :finmoji_tag)
-
assert Formatter.get_emoji(text) == [
- {"moominmamma", "/finmoji/128px/moominmamma-128.png", tag}
+ {"moominmamma", "/finmoji/128px/moominmamma-128.png", "Finmoji"}
]
end
--
cgit v1.2.3
From a14742f495fac78f4dfd7ab02f4c3ae5c7c37c3b Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 16:30:11 +0700
Subject: add `user delete_activities` mix task
---
lib/mix/tasks/pleroma/user.ex | 8 ++++++--
lib/pleroma/user.ex | 33 +++++++++++++++++----------------
test/tasks/user_test.exs | 10 ++++++++++
test/user_test.exs | 10 ++++++++++
4 files changed, 43 insertions(+), 18 deletions(-)
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 680422c19..62c9fceda 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -23,7 +23,7 @@ defmodule Mix.Tasks.Pleroma.User do
- `--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
+ - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
## Generate an invite link.
@@ -33,6 +33,10 @@ defmodule Mix.Tasks.Pleroma.User do
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
@@ -309,7 +313,7 @@ defmodule Mix.Tasks.Pleroma.User do
with %User{local: true} = user <- User.get_by_nickname(nickname) do
User.delete_user_activities(user)
- Mix.shell().info("User #{nickname} statuses deleted..")
+ Mix.shell().info("User #{nickname} statuses deleted.")
else
_ ->
Mix.shell().error("No local user #{nickname}")
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 18cf374dd..a180c1a8b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1088,29 +1088,30 @@ defmodule Pleroma.User do
# Remove all relationships
{:ok, followers} = User.get_followers(user)
- followers
- |> Enum.each(fn follower -> User.unfollow(follower, user) end)
+ Enum.each(followers, fn follower -> User.unfollow(follower, user) end)
{:ok, friends} = User.get_friends(user)
- friends
- |> Enum.each(fn followed -> User.unfollow(user, followed) end)
+ Enum.each(friends, fn followed -> User.unfollow(user, followed) end)
- query =
- from(a in Activity, where: a.actor == ^user.ap_id)
- |> Activity.with_preloaded_object()
+ delete_user_activities(user)
+ end
- Repo.all(query)
- |> Enum.each(fn activity ->
- case activity.data["type"] do
- "Create" ->
- ActivityPub.delete(Object.normalize(activity))
+ def delete_user_activities(%User{ap_id: ap_id} = user) do
+ Activity
+ |> where(actor: ^ap_id)
+ |> Activity.with_preloaded_object()
+ |> Repo.all()
+ |> Enum.each(fn
+ %{data: %{"type" => "Create"}} = activity ->
+ activity |> Object.normalize() |> ActivityPub.delete()
- # TODO: Do something with likes, follows, repeats.
- _ ->
- "Doing nothing"
- end
+ # TODO: Do something with likes, follows, repeats.
+ _ ->
+ "Doing nothing"
end)
+
+ {:ok, user}
end
def html_filter_policy(%User{info: %{no_rich_text: true}}) do
diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs
index 7b814d171..1030bd555 100644
--- a/test/tasks/user_test.exs
+++ b/test/tasks/user_test.exs
@@ -248,4 +248,14 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert message =~ "Generated"
end
end
+
+ describe "running delete_activities" do
+ test "activities are deleted" do
+ %{nickname: nickname} = insert(:user)
+
+ assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname])
+ assert_received {:mix_shell, :info, [message]}
+ assert message == "User #{nickname} statuses deleted."
+ end
+ end
end
diff --git a/test/user_test.exs b/test/user_test.exs
index 8cf2ba6ab..a6fd35ede 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -792,6 +792,16 @@ defmodule Pleroma.UserTest do
assert false == user.info.deactivated
end
+ test ".delete_user_activities deletes all create activities" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
+ {:ok, _} = User.delete_user_activities(user)
+
+ # TODO: Remove favorites, repeats, delete activities.
+ refute Activity.get_by_id(activity.id)
+ end
+
test ".delete deactivates a user, all follow relationships and all create activities" do
user = insert(:user)
followed = insert(:user)
--
cgit v1.2.3
From 3db923515057b7da23e4bb58a1696cd14df7ed52 Mon Sep 17 00:00:00 2001
From: Sergey Suprunenko
Date: Tue, 2 Apr 2019 11:25:51 +0200
Subject: Ignore dates in wrong formats
---
lib/pleroma/web/common_api/utils.ex | 21 ++++++-----------
test/web/common_api/common_api_utils_test.exs | 33 +++++++++++++--------------
2 files changed, 23 insertions(+), 31 deletions(-)
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 3f5348d66..0bf4de2f6 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -15,6 +15,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
+ require Logger
+
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
activity =
@@ -240,28 +242,19 @@ defmodule Pleroma.Web.CommonAPI.Utils do
Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y")
end
- def date_to_asctime(date) when is_float(date) do
- date
- |> trunc()
- |> date_to_asctime()
- end
-
- def date_to_asctime(date) when is_integer(date) do
- with {:ok, date} <- DateTime.from_unix(date) do
+ def date_to_asctime(date) when is_binary(date) do
+ with {:ok, date, _offset} <- DateTime.from_iso8601(date) do
format_asctime(date)
else
_e ->
+ Logger.warn("Date #{date} in wrong format, must be ISO 8601")
""
end
end
def date_to_asctime(date) do
- with {:ok, date, _offset} <- DateTime.from_iso8601(date) do
- format_asctime(date)
- else
- _e ->
- ""
- end
+ Logger.warn("Date #{date} in wrong format, must be ISO 8601")
+ ""
end
def to_masto_date(%NaiveDateTime{} = date) do
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index 0f8b28d9c..f0c59d5c3 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -155,39 +155,38 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
end
describe "formats date to asctime" do
- test "when date is an integer Unix timestamp" do
- date = DateTime.utc_now() |> DateTime.to_unix()
+ test "when date is in ISO 8601 format" do
+ date = DateTime.utc_now() |> DateTime.to_iso8601()
expected =
date
- |> DateTime.from_unix!()
+ |> DateTime.from_iso8601()
+ |> elem(1)
|> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
assert Utils.date_to_asctime(date) == expected
end
- test "when date is a float Unix timestamp" do
- date = 1_553_808_404.602961
+ test "when date is a binary in wrong format" do
+ date = DateTime.utc_now()
- expected =
- date
- |> trunc()
- |> DateTime.from_unix!()
- |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+ expected = ""
assert Utils.date_to_asctime(date) == expected
end
- test "when date is in ISO 8601 format" do
- date = DateTime.utc_now() |> DateTime.to_iso8601()
+ test "when date is a Unix timestamp" do
+ date = DateTime.utc_now() |> DateTime.to_unix()
- expected =
- date
- |> DateTime.from_iso8601()
- |> elem(1)
- |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+ expected = ""
assert Utils.date_to_asctime(date) == expected
end
+
+ test "when date is nil" do
+ expected = ""
+
+ assert Utils.date_to_asctime(nil) == expected
+ end
end
end
--
cgit v1.2.3
From 4212527928020de5b67424f090c67fc20d0844af Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 16:50:31 +0700
Subject: change `Repo.get(Activity, id)` => `Activity.get_by_id(id)`
---
lib/pleroma/gopher/server.ex | 3 +--
lib/pleroma/web/activity_pub/utils.ex | 2 +-
lib/pleroma/web/common_api/utils.ex | 2 +-
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 14 +++++++-------
lib/pleroma/web/twitter_api/twitter_api.ex | 2 +-
lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 ++--
6 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
index 3b9629d77..6a56a6f67 100644
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -38,7 +38,6 @@ end
defmodule Pleroma.Gopher.Server.ProtocolHandler do
alias Pleroma.Activity
alias Pleroma.HTML
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
@@ -111,7 +110,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
end
def response("/notices/" <> id) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.is_public?(activity) do
activities =
ActivityPub.fetch_activities_for_context(activity.data["context"])
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 2e9ffe41c..77841278a 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -354,7 +354,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
[state, actor, object]
)
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
{:ok, activity}
rescue
e ->
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index f596f703b..4c338de12 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def get_replied_to_activity(""), do: nil
def get_replied_to_activity(id) when not is_nil(id) do
- Repo.get(Activity, id)
+ Activity.get_by_id(id)
end
def get_replied_to_activity(_), do: nil
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index eee4e7678..18e4ddb88 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -319,7 +319,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(StatusView)
@@ -328,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
activities <-
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
"blocking_user" => user,
@@ -460,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
@@ -471,7 +471,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
@@ -593,7 +593,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def favourited_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^likes)
users = Repo.all(q)
@@ -606,7 +606,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reblogged_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^announces)
users = Repo.all(q)
@@ -1454,7 +1454,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
- with %Activity{} = activity <- Repo.get(Activity, status_id),
+ with %Activity{} = activity <- Activity.get_by_id(status_id),
true <- Visibility.visible_for_user?(activity, user) do
data =
StatusView.render(
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 9978c7f64..d0e58e71b 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
def delete(%User{} = user, id) do
- with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id),
+ with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id),
{:ok, activity} <- CommonAPI.delete(id, user) do
{:ok, activity}
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 62cce18dc..eebd4dcd3 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -270,7 +270,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(ActivityView)
@@ -342,7 +342,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
+ activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
if activity.data["type"] == "Create" do
activity
--
cgit v1.2.3
From 1b3d92192194baf6b431cd9f0ce58062d1b703d5 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 17:01:26 +0700
Subject: change `Repo.get(User, id)` => `User.get_by_id(id)`
---
lib/mix/tasks/pleroma/user.ex | 7 +++--
lib/pleroma/PasswordResetToken.ex | 2 +-
lib/pleroma/list.ex | 2 +-
lib/pleroma/user.ex | 8 +++---
lib/pleroma/web/channels/user_socket.ex | 2 +-
lib/pleroma/web/common_api/utils.ex | 2 +-
.../web/mastodon_api/mastodon_api_controller.ex | 30 +++++++++++-----------
lib/pleroma/web/mastodon_api/websocket_handler.ex | 2 +-
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
lib/pleroma/web/oauth/token.ex | 2 +-
lib/pleroma/web/streamer.ex | 3 +--
.../web/twitter_api/controllers/util_controller.ex | 8 +++---
.../web/twitter_api/twitter_api_controller.ex | 6 ++---
test/user_test.exs | 18 ++++++-------
.../activity_pub/activity_pub_controller_test.exs | 9 +++----
test/web/activity_pub/activity_pub_test.exs | 20 +++++++--------
test/web/activity_pub/transmogrifier_test.exs | 20 +++++++--------
test/web/admin_api/admin_api_controller_test.exs | 17 ++++++------
.../mastodon_api/mastodon_api_controller_test.exs | 28 ++++++++++----------
test/web/mastodon_api/notification_view_test.exs | 2 +-
test/web/ostatus/ostatus_test.exs | 2 +-
.../twitter_api/twitter_api_controller_test.exs | 30 +++++++++++-----------
test/web/twitter_api/views/user_view_test.exs | 2 +-
23 files changed, 110 insertions(+), 114 deletions(-)
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index f6cca0d06..2487b4ab5 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -6,7 +6,6 @@ defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Ecto.Changeset
alias Mix.Tasks.Pleroma.Common
- alias Pleroma.Repo
alias Pleroma.User
@shortdoc "Manages Pleroma users"
@@ -23,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.User do
- `--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
+ - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
## Generate an invite link.
@@ -202,7 +201,7 @@ defmodule Mix.Tasks.Pleroma.User do
{:ok, friends} = User.get_friends(user)
Enum.each(friends, fn friend ->
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
User.unfollow(user, friend)
@@ -210,7 +209,7 @@ defmodule Mix.Tasks.Pleroma.User do
:timer.sleep(500)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
if Enum.empty?(user.following) do
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
index 772c239a1..7afbc8751 100644
--- a/lib/pleroma/PasswordResetToken.ex
+++ b/lib/pleroma/PasswordResetToken.ex
@@ -39,7 +39,7 @@ defmodule Pleroma.PasswordResetToken do
def reset_password(token, data) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id),
+ %User{} = user <- User.get_by_id(token.user_id),
{:ok, _user} <- User.reset_password(user, data),
{:ok, token} <- Repo.update(used_changeset(token)) do
{:ok, token}
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index 55c4cf6df..110be8355 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -80,7 +80,7 @@ defmodule Pleroma.List do
# Get lists to which the account belongs.
def get_lists_account_belongs(%User{} = owner, account_id) do
- user = Repo.get(User, account_id)
+ user = User.get_by_id(account_id)
query =
from(
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 728b00a56..eb305dd95 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1231,8 +1231,8 @@ defmodule Pleroma.User do
# this is because we have synchronous follow APIs and need to simulate them
# with an async handshake
def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
- with %User{} = a <- Repo.get(User, a.id),
- %User{} = b <- Repo.get(User, b.id) do
+ with %User{} = a <- User.get_by_id(a.id),
+ %User{} = b <- User.get_by_id(b.id) do
{:ok, a, b}
else
_e ->
@@ -1242,8 +1242,8 @@ defmodule Pleroma.User do
def wait_and_refresh(timeout, %User{} = a, %User{} = b) do
with :ok <- :timer.sleep(timeout),
- %User{} = a <- Repo.get(User, a.id),
- %User{} = b <- Repo.get(User, b.id) do
+ %User{} = a <- User.get_by_id(a.id),
+ %User{} = b <- User.get_by_id(b.id) do
{:ok, a, b}
else
_e ->
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 3a700fa3b..6503979a1 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.UserSocket do
def connect(%{"token" => token}, socket) do
with true <- Pleroma.Config.get([:chat, :enabled]),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
- %User{} = user <- Pleroma.Repo.get(User, user_id) do
+ %User{} = user <- Pleroma.User.get_by_id(user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else
_e -> :error
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 4c338de12..40cea3090 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -275,7 +275,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
def confirm_current_password(user, password) do
- with %User{local: true} = db_user <- Repo.get(User, user.id),
+ with %User{local: true} = db_user <- User.get_by_id(user.id),
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
{:ok, db_user}
else
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 18e4ddb88..da96d1674 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -285,7 +285,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- Repo.get(User, params["id"]) do
+ with %User{} = user <- User.get_by_id(params["id"]) do
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
@@ -657,7 +657,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- Repo.get(User, id),
+ with %User{} = user <- User.get_by_id(id),
followers <- MastodonAPI.get_followers(user, params) do
followers =
cond do
@@ -674,7 +674,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- Repo.get(User, id),
+ with %User{} = user <- User.get_by_id(id),
followers <- MastodonAPI.get_friends(user, params) do
followers =
cond do
@@ -699,7 +699,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
+ with %User{} = follower <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -713,7 +713,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
+ with %User{} = follower <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -727,7 +727,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
+ with %User{} = followed <- User.get_by_id(id),
false <- User.following?(follower, followed),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
@@ -769,7 +769,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
+ with %User{} = followed <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.unfollow(follower, followed) do
conn
|> put_view(AccountView)
@@ -778,7 +778,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.mute(muter, muted) do
conn
|> put_view(AccountView)
@@ -792,7 +792,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.unmute(muter, muted) do
conn
|> put_view(AccountView)
@@ -813,7 +813,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.block(blocker, blocked),
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
conn
@@ -828,7 +828,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.unblock(blocker, blocked),
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
conn
@@ -966,7 +966,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def bookmarks(%{assigns: %{user: user}} = conn, _) do
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
activities =
user.bookmarks
@@ -1023,7 +1023,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(User, account_id) do
+ %User{} = followed <- User.get_by_id(account_id) do
Pleroma.List.follow(list, followed)
end
end)
@@ -1035,7 +1035,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(Pleroma.User, account_id) do
+ %User{} = followed <- Pleroma.User.get_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
@@ -1312,7 +1312,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Logger.debug("Unimplemented, returning unmodified relationship")
- with %User{} = target <- Repo.get(User, id) do
+ with %User{} = target <- User.get_by_id(id) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: target})
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 9b262f461..1b3721e2b 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
# Authenticated streams.
defp allow_request(stream, {"access_token", access_token}) when stream in @streams do
with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
- user = %User{} <- Repo.get(User, user_id) do
+ user = %User{} <- User.get_by_id(user_id) do
{:ok, user}
else
_ -> {:error, 403}
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index ebb3dd253..75506e168 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -108,7 +108,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
fixed_token = fix_padding(params["code"]),
%Authorization{} = auth <-
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
- %User{} = user <- Repo.get(User, auth.user_id),
+ %User{} = user <- User.get_by_id(auth.user_id),
{:ok, token} <- Token.exchange_token(app, auth),
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
response = %{
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index a8b06db36..2b5ad9b94 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
- create_token(app, Repo.get(User, auth.user_id), auth.scopes)
+ create_token(app, User.get_by_id(auth.user_id), auth.scopes)
end
end
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 592749b42..a82109f92 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.Streamer do
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
@@ -82,7 +81,7 @@ defmodule Pleroma.Web.Streamer do
_ ->
Pleroma.List.get_lists_from_activity(item)
|> Enum.filter(fn list ->
- owner = Repo.get(User, list.user_id)
+ owner = User.get_by_id(list.user_id)
Visibility.visible_for_user?(item, owner)
end)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index faa733fec..e817f0d79 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id) do
+ %User{} = user <- User.get_by_id(token.user_id) do
render(conn, "password_reset.html", %{
token: token,
user: user
@@ -96,13 +96,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
- followee = Repo.get(User, id)
+ followee = User.get_by_id(id)
avatar = User.avatar_url(followee)
name = followee.nickname
with %User{} = user <- User.get_cached_by_nickname(username),
true <- Pbkdf2.checkpw(password, user.password_hash),
- %User{} = _followed <- Repo.get(User, id),
+ %User{} = _followed <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -124,7 +124,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with %User{} = followee <- Repo.get(User, id),
+ with %User{} = followee <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index eebd4dcd3..a7ec9949c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -434,7 +434,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
- with %User{} = user <- Repo.get(User, uid),
+ with %User{} = user <- User.get_by_id(uid),
true <- user.local,
true <- user.info.confirmation_pending,
true <- user.info.confirmation_token == token,
@@ -587,7 +587,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
+ %User{} = follower <- User.get_by_id(uid),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(UserView)
@@ -599,7 +599,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
+ %User{} = follower <- User.get_by_id(uid),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(UserView)
diff --git a/test/user_test.exs b/test/user_test.exs
index 8cf2ba6ab..0f5cd65c9 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -122,7 +122,7 @@ defmodule Pleroma.UserTest do
{:ok, user} = User.follow(user, followed)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
followed = User.get_by_ap_id(followed.ap_id)
assert followed.info.follower_count == 1
@@ -178,7 +178,7 @@ defmodule Pleroma.UserTest do
{:ok, user, _activity} = User.unfollow(user, followed)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.following == []
end
@@ -188,7 +188,7 @@ defmodule Pleroma.UserTest do
{:error, _} = User.unfollow(user, user)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.following == [user.ap_id]
end
@@ -679,7 +679,7 @@ defmodule Pleroma.UserTest do
assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -697,7 +697,7 @@ defmodule Pleroma.UserTest do
refute User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -715,7 +715,7 @@ defmodule Pleroma.UserTest do
assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -809,9 +809,9 @@ defmodule Pleroma.UserTest do
{:ok, _} = User.delete(user)
- followed = Repo.get(User, followed.id)
- follower = Repo.get(User, follower.id)
- user = Repo.get(User, user.id)
+ followed = User.get_by_id(followed.id)
+ follower = User.get_by_id(follower.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index a1e83b380..8dd8e7e0a 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
alias Pleroma.Activity
alias Pleroma.Instances
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.UserView
@@ -51,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("accept", "application/json")
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -66,7 +65,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -84,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
)
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -543,7 +542,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user)
Enum.each(1..15, fn _ ->
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
other_user = insert(:user)
User.follow(user, other_user)
end)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index ac5fbe0a9..c2dce3b78 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -218,18 +218,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user = insert(:user)
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 2
end
@@ -758,23 +758,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user = insert(:user, info: %{note_count: 10})
{:ok, a1} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"})
{:ok, a2} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"})
{:ok, a3} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"})
{:ok, a4} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "direct"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"})
{:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 10
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 50e8e40bd..43970cac3 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -639,7 +639,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -661,7 +661,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -681,7 +681,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -700,7 +700,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
:error = Transmogrifier.handle_incoming(accept_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
refute User.following?(follower, followed) == true
end
@@ -719,7 +719,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
:error = Transmogrifier.handle_incoming(accept_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
refute User.following?(follower, followed) == true
end
@@ -744,7 +744,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = Transmogrifier.handle_incoming(reject_data)
refute activity.local
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == false
end
@@ -766,7 +766,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == false
end
@@ -1020,7 +1020,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 1
{:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
@@ -1031,7 +1031,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
# Wait for the background task
:timer.sleep(1000)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 1
activity = Repo.get(Activity, activity.id)
@@ -1060,7 +1060,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
unrelated_activity = Repo.get(Activity, unrelated_activity.id)
refute user.follower_address in unrelated_activity.recipients
- user_two = Repo.get(User, user_two.id)
+ user_two = User.get_by_id(user_two.id)
assert user.follower_address in user_two.following
refute "..." in user_two.following
end
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 2f53416a3..acae64361 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -5,7 +5,6 @@
defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
use Pleroma.Web.ConnCase
- alias Pleroma.Repo
alias Pleroma.User
import Pleroma.Factory
@@ -101,13 +100,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
user2: user2
} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user1.id).tags == ["x", "foo", "bar"]
- assert Repo.get(User, user2.id).tags == ["y", "foo", "bar"]
+ assert User.get_by_id(user1.id).tags == ["x", "foo", "bar"]
+ assert User.get_by_id(user2.id).tags == ["y", "foo", "bar"]
end
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user3.id).tags == ["unchanged"]
+ assert User.get_by_id(user3.id).tags == ["unchanged"]
end
end
@@ -137,13 +136,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
user2: user2
} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user1.id).tags == []
- assert Repo.get(User, user2.id).tags == ["y"]
+ assert User.get_by_id(user1.id).tags == []
+ assert User.get_by_id(user2.id).tags == ["y"]
end
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user3.id).tags == ["unchanged"]
+ assert User.get_by_id(user3.id).tags == ["unchanged"]
end
end
@@ -213,7 +212,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn
|> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated == true
assert json_response(conn, :no_content)
end
@@ -225,7 +224,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn
|> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: true})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated == false
assert json_response(conn, :no_content)
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..3ac970516 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -1112,8 +1112,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1132,8 +1132,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1145,8 +1145,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == true
end
@@ -1169,7 +1169,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1179,8 +1179,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
end
@@ -1465,7 +1465,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"id" => _id, "following" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1474,7 +1474,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"id" => _id, "following" => false} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1496,7 +1496,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1532,7 +1532,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1889,7 +1889,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
# Stats should count users with missing or nil `info.deactivated` value
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
info_change = Changeset.change(user.info, %{deactivated: nil})
{:ok, _user} =
diff --git a/test/web/mastodon_api/notification_view_test.exs b/test/web/mastodon_api/notification_view_test.exs
index b826a7e61..dc747e327 100644
--- a/test/web/mastodon_api/notification_view_test.exs
+++ b/test/web/mastodon_api/notification_view_test.exs
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
mentioned_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{mentioned_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
expected = %{
id: to_string(notification.id),
diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs
index 76b90e186..7b0b43a9d 100644
--- a/test/web/ostatus/ostatus_test.exs
+++ b/test/web/ostatus/ostatus_test.exs
@@ -344,7 +344,7 @@ defmodule Pleroma.Web.OStatusTest do
{:ok, user} = OStatus.find_or_make_user(uri)
- user = Repo.get(Pleroma.User, user.id)
+ user = Pleroma.User.get_by_id(user.id)
assert user.name == "Constance Variable"
assert user.nickname == "lambadalambda@social.heldscal.la"
assert user.local == false
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 083540017..5987d0c7c 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -719,7 +719,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/create.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert User.ap_followers(followed) in current_user.following
assert json_response(conn, 200) ==
@@ -734,8 +734,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/create.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
- followed = Repo.get(User, followed.id)
+ current_user = User.get_by_id(current_user.id)
+ followed = User.get_by_id(followed.id)
refute User.ap_followers(followed) in current_user.following
@@ -764,7 +764,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/destroy.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert current_user.following == [current_user.ap_id]
assert json_response(conn, 200) ==
@@ -788,7 +788,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/blocks/create.json", %{user_id: blocked.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert User.blocks?(current_user, blocked)
assert json_response(conn, 200) ==
@@ -815,7 +815,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/blocks/destroy.json", %{user_id: blocked.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert current_user.info.blocks == []
assert json_response(conn, 200) ==
@@ -846,7 +846,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert is_map(current_user.avatar)
assert json_response(conn, 200) ==
@@ -1109,7 +1109,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
test "it confirms the user account", %{conn: conn, user: user} do
get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
refute user.info.confirmation_pending
refute user.info.confirmation_token
@@ -1727,7 +1727,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
})
assert json_response(conn, 200) == %{"status" => "success"}
- fetched_user = Repo.get(User, current_user.id)
+ fetched_user = User.get_by_id(current_user.id)
assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true
end
end
@@ -1768,8 +1768,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1808,8 +1808,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1831,8 +1831,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 4e7f94795..0feaf4b64 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -292,7 +292,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
}
}
- blocker = Repo.get(User, blocker.id)
+ blocker = User.get_by_id(blocker.id)
assert represented == UserView.render("show.json", %{user: user, for: blocker})
end
--
cgit v1.2.3
From 11c2d6bdc458d40616e677ff71e471bd827344ee Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 17:08:03 +0700
Subject: change `Repo.get(Activity, id)` => `Activity.get_by_id(id)` in tests
---
test/user_test.exs | 2 +-
test/web/activity_pub/activity_pub_test.exs | 10 +++++-----
test/web/activity_pub/transmogrifier_test.exs | 8 ++++----
.../mastodon_api/mastodon_api_controller_test.exs | 20 ++++++++++----------
test/web/mastodon_api/notification_view_test.exs | 4 ++--
test/web/ostatus/activity_representer_test.exs | 4 ++--
.../incoming_documents/delete_handling_test.exs | 7 +++----
test/web/ostatus/ostatus_test.exs | 4 ++--
test/web/twitter_api/twitter_api_controller_test.exs | 4 ++--
test/web/twitter_api/views/activity_view_test.exs | 2 +-
10 files changed, 32 insertions(+), 33 deletions(-)
diff --git a/test/user_test.exs b/test/user_test.exs
index 0f5cd65c9..f340bde61 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -820,7 +820,7 @@ defmodule Pleroma.UserTest do
# TODO: Remove favorites, repeats, delete activities.
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "get_public_key_for_ap_id fetches a user that's not in the db" do
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index c2dce3b78..7969c8035 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -322,7 +322,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
- activity_three = Repo.get(Activity, activity_three.id)
+ activity_three = Activity.get_by_id(activity_three.id)
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@@ -380,7 +380,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
- activity_three = Repo.get(Activity, activity_three.id)
+ activity_three = Activity.get_by_id(activity_three.id)
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@@ -559,7 +559,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, _, _, object} = ActivityPub.unlike(user, object)
assert object.data["like_count"] == 0
- assert Repo.get(Activity, like_activity.id) == nil
+ assert Activity.get_by_id(like_activity.id) == nil
end
end
@@ -610,7 +610,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert unannounce_activity.data["actor"] == user.ap_id
assert unannounce_activity.data["context"] == announce_activity.data["context"]
- assert Repo.get(Activity, announce_activity.id) == nil
+ assert Activity.get_by_id(announce_activity.id) == nil
end
end
@@ -749,7 +749,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert delete.data["actor"] == note.data["actor"]
assert delete.data["object"] == note.data["object"]["id"]
- assert Repo.get(Activity, delete.id) != nil
+ assert Activity.get_by_id(delete.id) != nil
assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 43970cac3..62b973c4f 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -461,7 +461,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "it fails for incoming deletes with spoofed origin" do
@@ -481,7 +481,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
:error = Transmogrifier.handle_incoming(data)
- assert Repo.get(Activity, activity.id)
+ assert Activity.get_by_id(activity.id)
end
test "it works for incoming unannounces with an existing notice" do
@@ -1034,7 +1034,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
user = User.get_by_id(user.id)
assert user.info.note_count == 1
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
assert user.follower_address in activity.recipients
assert %{
@@ -1057,7 +1057,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
refute "..." in activity.recipients
- unrelated_activity = Repo.get(Activity, unrelated_activity.id)
+ unrelated_activity = Activity.get_by_id(unrelated_activity.id)
refute user.follower_address in unrelated_activity.recipients
user_two = User.get_by_id(user_two.id)
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 3ac970516..dcb73a6c2 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -101,7 +101,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
json_response(conn_one, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
conn_two =
conn
@@ -140,7 +140,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
end
test "posting a status with OGP link preview", %{conn: conn} do
@@ -155,7 +155,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
})
assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
Pleroma.Config.put([:rich_media, :enabled], false)
end
@@ -170,7 +170,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
- assert activity = Repo.get(Activity, id)
+ assert activity = Activity.get_by_id(id)
assert activity.recipients == [user2.ap_id, user1.ap_id]
assert activity.data["to"] == [user2.ap_id]
assert activity.data["cc"] == []
@@ -289,7 +289,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- activity = Repo.get(Activity, id)
+ activity = Activity.get_by_id(id)
assert activity.data["context"] == replied_to.data["context"]
assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
@@ -305,7 +305,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- activity = Repo.get(Activity, id)
+ activity = Activity.get_by_id(id)
assert activity
end
@@ -404,7 +404,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{} = json_response(conn, 200)
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "when you didn't create it", %{conn: conn} do
@@ -418,7 +418,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"error" => _} = json_response(conn, 403)
- assert Repo.get(Activity, activity.id) == activity
+ assert Activity.get_by_id(activity.id) == activity
end
test "when you're an admin or moderator", %{conn: conn} do
@@ -441,8 +441,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{} = json_response(res_conn, 200)
- refute Repo.get(Activity, activity1.id)
- refute Repo.get(Activity, activity2.id)
+ refute Activity.get_by_id(activity1.id)
+ refute Activity.get_by_id(activity2.id)
end
end
diff --git a/test/web/mastodon_api/notification_view_test.exs b/test/web/mastodon_api/notification_view_test.exs
index dc747e327..f2c1eb76c 100644
--- a/test/web/mastodon_api/notification_view_test.exs
+++ b/test/web/mastodon_api/notification_view_test.exs
@@ -44,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(favorite_activity)
- create_activity = Repo.get(Activity, create_activity.id)
+ create_activity = Activity.get_by_id(create_activity.id)
expected = %{
id: to_string(notification.id),
@@ -66,7 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(reblog_activity)
- reblog_activity = Repo.get(Activity, create_activity.id)
+ reblog_activity = Activity.get_by_id(create_activity.id)
expected = %{
id: to_string(notification.id),
diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs
index 5cb135b4c..a4bb68c4d 100644
--- a/test/web/ostatus/activity_representer_test.exs
+++ b/test/web/ostatus/activity_representer_test.exs
@@ -116,10 +116,10 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
{:ok, announce, _object} = ActivityPub.announce(user, object)
- announce = Repo.get(Activity, announce.id)
+ announce = Activity.get_by_id(announce.id)
note_user = User.get_cached_by_ap_id(note.data["actor"])
- note = Repo.get(Activity, note.id)
+ note = Activity.get_by_id(note.id)
note_xml =
ActivityRepresenter.to_simple_form(note, note_user, true)
diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs
index 412d894fd..ca6e61339 100644
--- a/test/web/ostatus/incoming_documents/delete_handling_test.exs
+++ b/test/web/ostatus/incoming_documents/delete_handling_test.exs
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
alias Pleroma.Activity
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.Web.OStatus
setup do
@@ -32,10 +31,10 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
{:ok, [delete]} = OStatus.handle_incoming(incoming)
- refute Repo.get(Activity, note.id)
- refute Repo.get(Activity, like.id)
+ refute Activity.get_by_id(note.id)
+ refute Activity.get_by_id(like.id)
assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
- assert Repo.get(Activity, second_note.id)
+ assert Activity.get_by_id(second_note.id)
assert Object.get_by_ap_id(second_note.data["object"]["id"])
assert delete.data["type"] == "Delete"
diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs
index 7b0b43a9d..9fd100f63 100644
--- a/test/web/ostatus/ostatus_test.exs
+++ b/test/web/ostatus/ostatus_test.exs
@@ -154,7 +154,7 @@ defmodule Pleroma.Web.OStatusTest do
assert "https://pleroma.soykaf.com/users/lain" in activity.data["to"]
refute activity.local
- retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+ retweeted_activity = Activity.get_by_id(retweeted_activity.id)
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
refute retweeted_activity.local
@@ -181,7 +181,7 @@ defmodule Pleroma.Web.OStatusTest do
assert user.ap_id in activity.data["to"]
refute activity.local
- retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+ retweeted_activity = Activity.get_by_id(retweeted_activity.id)
assert note_activity.id == retweeted_activity.id
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == user.ap_id
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 5987d0c7c..dffd401f7 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -954,7 +954,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post(request_path)
- activity = Repo.get(Activity, note_activity.id)
+ activity = Activity.get_by_id(note_activity.id)
activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
assert json_response(response, 200) ==
@@ -992,7 +992,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> with_credentials(current_user.nickname, "test")
|> post(request_path)
- activity = Repo.get(Activity, note_activity.id)
+ activity = Activity.get_by_id(note_activity.id)
activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
assert json_response(response, 200) ==
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index a1776b3e6..ee9a0c834 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -281,7 +281,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
convo_id = Utils.context_to_conversation_id(activity.data["object"]["context"])
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
result = ActivityView.render("activity.json", activity: announce)
--
cgit v1.2.3
From 15ce7104608869cb62c72c5beef0b23b1150cda0 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Tue, 2 Apr 2019 13:43:33 +0300
Subject: Added "GET /oauth/authorize" tests.
---
test/support/factory.ex | 2 +-
test/web/oauth/oauth_controller_test.exs | 514 ++++++++++++++++++-------------
2 files changed, 297 insertions(+), 219 deletions(-)
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 18f77f01a..e1a08315a 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -216,7 +216,7 @@ defmodule Pleroma.Factory do
redirect_uris: "https://example.com/callback",
scopes: ["read", "write", "follow", "push"],
website: "https://example.com",
- client_id: "aaabbb==",
+ client_id: Ecto.UUID.generate(),
client_secret: "aaa;/&bbb"
}
end
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 84ec7b4ee..a9a0b9ed4 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -10,261 +10,339 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- test "redirects with oauth authorization" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write", "follow"])
-
- conn =
- build_conn()
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "scope" => "read write",
- "state" => "statepassed"
- }
- })
+ describe "GET /oauth/authorize" do
+ setup do
+ session_opts = [
+ store: :cookie,
+ key: "_test",
+ signing_salt: "cooldude"
+ ]
+
+ [
+ app: insert(:oauth_app, redirect_uris: "https://redirect.url"),
+ conn:
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(session_opts))
+ |> fetch_session()
+ ]
+ end
- target = redirected_to(conn)
- assert target =~ app.redirect_uris
+ test "renders authentication page", %{app: app, conn: conn} do
+ conn =
+ get(
+ conn,
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read"
+ }
+ )
+
+ assert html_response(conn, 200) =~ ~s(type="submit")
+ end
- query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+ test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
+ %{app: app, conn: conn} do
+ token = insert(:oauth_token, app_id: app.id)
+
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read",
+ "force_login" => "true"
+ }
+ )
+
+ assert html_response(conn, 200) =~ ~s(type="submit")
+ end
- assert %{"state" => "statepassed", "code" => code} = query
- auth = Repo.get_by(Authorization, token: code)
- assert auth
- assert auth.scopes == ["read", "write"]
+ test "redirects to app if user is already authenticated", %{app: app, conn: conn} do
+ token = insert(:oauth_token, app_id: app.id)
+
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read"
+ }
+ )
+
+ assert redirected_to(conn) == "https://redirect.url"
+ end
end
- test "returns 401 for wrong credentials", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app)
+ describe "POST /oauth/authorize" do
+ test "redirects with oauth authorization" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write", "follow"])
+
+ conn =
+ build_conn()
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read write",
+ "state" => "statepassed"
+ }
+ })
+
+ target = redirected_to(conn)
+ assert target =~ app.redirect_uris
+
+ query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+ assert %{"state" => "statepassed", "code" => code} = query
+ auth = Repo.get_by(Authorization, token: code)
+ assert auth
+ assert auth.scopes == ["read", "write"]
+ end
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "wrong",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => Enum.join(app.scopes, " ")
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "Invalid Username/Password"
- end
+ test "returns 401 for wrong credentials", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "wrong",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => Enum.join(app.scopes, " ")
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "Invalid Username/Password"
+ end
- test "returns 401 for missing scopes", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app)
+ test "returns 401 for missing scopes", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => ""
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "This action is outside the authorized scopes"
+ end
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => ""
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "This action is outside the authorized scopes"
+ test "returns 401 for scopes beyond app scopes", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write"])
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => "read write follow"
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "This action is outside the authorized scopes"
+ end
end
- test "returns 401 for scopes beyond app scopes", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write"])
+ describe "POST /oauth/token" do
+ test "issues a token for an all-body request" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write"])
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
+ {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
"redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => "read write follow"
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "This action is outside the authorized scopes"
- end
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
- test "issues a token for an all-body request" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write"])
+ assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
- {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == auth.scopes
+ assert user.ap_id == ap_id
+ end
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
+ test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
+ password = "testpassword"
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
- assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
+ app = insert(:oauth_app, scopes: ["read", "write"])
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == auth.scopes
- assert user.ap_id == ap_id
- end
+ # Note: "scope" param is intentionally omitted
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
- test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
- password = "testpassword"
- user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+ assert %{"access_token" => token} = json_response(conn, 200)
- app = insert(:oauth_app, scopes: ["read", "write"])
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == app.scopes
+ end
- # Note: "scope" param is intentionally omitted
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "password",
- "username" => user.nickname,
- "password" => password,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
+ test "issues a token for request with HTTP basic auth client credentials" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
- assert %{"access_token" => token} = json_response(conn, 200)
+ {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
+ assert auth.scopes == ["scope1", "scope2"]
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == app.scopes
- end
+ app_encoded =
+ (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
+ |> Base.encode64()
- test "issues a token for request with HTTP basic auth client credentials" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
+ conn =
+ build_conn()
+ |> put_req_header("authorization", "Basic " <> app_encoded)
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
+ "redirect_uri" => app.redirect_uris
+ })
- {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
- assert auth.scopes == ["scope1", "scope2"]
+ assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
- app_encoded =
- (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
- |> Base.encode64()
+ assert scope == "scope1 scope2"
- conn =
- build_conn()
- |> put_req_header("authorization", "Basic " <> app_encoded)
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris
- })
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == ["scope1", "scope2"]
+ end
- assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
+ test "rejects token exchange with invalid client credentials" do
+ user = insert(:user)
+ app = insert(:oauth_app)
- assert scope == "scope1 scope2"
+ {:ok, auth} = Authorization.create_authorization(app, user)
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == ["scope1", "scope2"]
- end
+ conn =
+ build_conn()
+ |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
+ "redirect_uri" => app.redirect_uris
+ })
- test "rejects token exchange with invalid client credentials" do
- user = insert(:user)
- app = insert(:oauth_app)
+ assert resp = json_response(conn, 400)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
+ end
- {:ok, auth} = Authorization.create_authorization(app, user)
+ test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
+ setting = Pleroma.Config.get([:instance, :account_activation_required])
- conn =
- build_conn()
- |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris
- })
+ unless setting do
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+ on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+ end
- assert resp = json_response(conn, 400)
- assert %{"error" => _} = resp
- refute Map.has_key?(resp, "access_token")
- end
+ password = "testpassword"
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+ info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
- test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
- setting = Pleroma.Config.get([:instance, :account_activation_required])
+ {:ok, user} =
+ user
+ |> Ecto.Changeset.change()
+ |> Ecto.Changeset.put_embed(:info, info_change)
+ |> Repo.update()
- unless setting do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+ refute Pleroma.User.auth_active?(user)
+
+ app = insert(:oauth_app)
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 403)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
end
- password = "testpassword"
- user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
- info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
-
- {:ok, user} =
- user
- |> Ecto.Changeset.change()
- |> Ecto.Changeset.put_embed(:info, info_change)
- |> Repo.update()
-
- refute Pleroma.User.auth_active?(user)
-
- app = insert(:oauth_app)
-
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "password",
- "username" => user.nickname,
- "password" => password,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
-
- assert resp = json_response(conn, 403)
- assert %{"error" => _} = resp
- refute Map.has_key?(resp, "access_token")
- end
+ test "rejects an invalid authorization code" do
+ app = insert(:oauth_app)
- test "rejects an invalid authorization code" do
- app = insert(:oauth_app)
-
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => "Imobviouslyinvalid",
- "redirect_uri" => app.redirect_uris,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
-
- assert resp = json_response(conn, 400)
- assert %{"error" => _} = json_response(conn, 400)
- refute Map.has_key?(resp, "access_token")
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => "Imobviouslyinvalid",
+ "redirect_uri" => app.redirect_uris,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 400)
+ assert %{"error" => _} = json_response(conn, 400)
+ refute Map.has_key?(resp, "access_token")
+ end
end
end
--
cgit v1.2.3
From 88d3cb44c3adc234ee828a8b50bc0c3857eb85a9 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 17:47:02 +0700
Subject: replace `Repo.get_by(User, nickname: nickname)` with
`User.get_by_nickname(nickname)`
---
lib/pleroma/plugs/user_fetcher_plug.ex | 22 ++--------------------
.../web/mastodon_api/mastodon_api_controller.ex | 2 +-
lib/pleroma/web/twitter_api/twitter_api.ex | 9 +++------
3 files changed, 6 insertions(+), 27 deletions(-)
diff --git a/lib/pleroma/plugs/user_fetcher_plug.ex b/lib/pleroma/plugs/user_fetcher_plug.ex
index 5a77f6833..4089aa958 100644
--- a/lib/pleroma/plugs/user_fetcher_plug.ex
+++ b/lib/pleroma/plugs/user_fetcher_plug.ex
@@ -3,9 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Plugs.UserFetcherPlug do
- alias Pleroma.Repo
alias Pleroma.User
-
import Plug.Conn
def init(options) do
@@ -14,26 +12,10 @@ defmodule Pleroma.Plugs.UserFetcherPlug do
def call(conn, _options) do
with %{auth_credentials: %{username: username}} <- conn.assigns,
- {:ok, %User{} = user} <- user_fetcher(username) do
- conn
- |> assign(:auth_user, user)
+ %User{} = user <- User.get_by_nickname_or_email(username) do
+ assign(conn, :auth_user, user)
else
_ -> conn
end
end
-
- defp user_fetcher(username_or_email) do
- {
- :ok,
- cond do
- # First, try logging in as if it was a name
- user = Repo.get_by(User, %{nickname: username_or_email}) ->
- user
-
- # If we get nil, we try using it as an email
- user = Repo.get_by(User, %{email: username_or_email}) ->
- user
- 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 da96d1674..ffd544644 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -755,7 +755,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
- with %User{} = followed <- Repo.get_by(User, nickname: uri),
+ with %User{} = followed <- User.get_by_nickname(uri),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index d0e58e71b..9b081a316 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -227,12 +227,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
%{"screen_name" => nickname} ->
- case target = Repo.get_by(User, nickname: nickname) do
- nil ->
- {:error, "No user with such screen_name"}
-
- _ ->
- {:ok, target}
+ case User.get_by_nickname(nickname) do
+ nil -> {:error, "No user with such screen_name"}
+ target -> {:ok, target}
end
_ ->
--
cgit v1.2.3
From 9a59c26619bada93e238f52e9432a93e54c04b5e Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 17:47:52 +0700
Subject: replace `Repo.get_by(User, ap_id: ap_id)` with
`User.get_by_ap_id(ap_id)`
---
test/web/activity_pub/activity_pub_test.exs | 4 ++--
test/web/mastodon_api/status_view_test.exs | 2 +-
test/web/salmon/salmon_test.exs | 2 +-
test/web/twitter_api/twitter_api_controller_test.exs | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 7969c8035..46b4cf7b6 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -638,8 +638,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "fetch the latest Follow" do
test "fetches the latest Follow activity" do
%Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
- follower = Repo.get_by(User, ap_id: activity.data["actor"])
- followed = Repo.get_by(User, ap_id: activity.data["object"])
+ follower = User.get_by_ap_id(activity.data["actor"])
+ followed = User.get_by_ap_id(activity.data["object"])
assert activity == Utils.fetch_latest_follow(follower, followed)
end
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index e1c9b2c8f..8db92ac16 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -175,7 +175,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("status.json", %{activity: activity})
- actor = Repo.get_by(User, ap_id: activity.actor)
+ actor = User.get_by_ap_id(activity.actor)
assert status.mentions ==
Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs
index 265e1abbd..35503259b 100644
--- a/test/web/salmon/salmon_test.exs
+++ b/test/web/salmon/salmon_test.exs
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
}
{:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]})
- user = Repo.get_by(User, ap_id: activity.data["actor"])
+ user = User.get_by_ap_id(activity.data["actor"])
{:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
poster = fn url, _data, _headers ->
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index dffd401f7..405f0cfae 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -955,7 +955,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> post(request_path)
activity = Activity.get_by_id(note_activity.id)
- activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
+ activity_user = User.get_by_ap_id(note_activity.data["actor"])
assert json_response(response, 200) ==
ActivityView.render("activity.json", %{
@@ -993,7 +993,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|> post(request_path)
activity = Activity.get_by_id(note_activity.id)
- activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
+ activity_user = User.get_by_ap_id(note_activity.data["actor"])
assert json_response(response, 200) ==
ActivityView.render("activity.json", %{
--
cgit v1.2.3
From 95c92c49c928340a479717aa171dcb83585f3275 Mon Sep 17 00:00:00 2001
From: cascode
Date: Tue, 2 Apr 2019 10:51:33 +0000
Subject: Fix account lookup for nicknames beginning with numbers
---
lib/pleroma/flake_id.ex | 2 +-
test/user_test.exs | 7 ++++++
.../mastodon_api/mastodon_api_controller_test.exs | 26 ++++++++++++++++++++++
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex
index 4259d5718..58ab3650d 100644
--- a/lib/pleroma/flake_id.ex
+++ b/lib/pleroma/flake_id.ex
@@ -46,7 +46,7 @@ defmodule Pleroma.FlakeId do
def from_string(string) when is_binary(string) and byte_size(string) < 18 do
case Integer.parse(string) do
- {id, _} -> <<0::integer-size(64), id::integer-size(64)>>
+ {id, ""} -> <<0::integer-size(64), id::integer-size(64)>>
_ -> nil
end
end
diff --git a/test/user_test.exs b/test/user_test.exs
index 8cf2ba6ab..e31b88b28 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -200,6 +200,13 @@ defmodule Pleroma.UserTest do
refute User.following?(followed, user)
end
+ test "fetches correct profile for nickname beginning with number" do
+ # Use old-style integer ID to try to reproduce the problem
+ user = insert(:user, %{id: 1080})
+ userwithnumbers = insert(:user, %{nickname: "#{user.id}garbage"})
+ assert userwithnumbers == User.get_cached_by_nickname_or_id(userwithnumbers.nickname)
+ end
+
describe "user registration" do
@full_user_data %{
bio: "A guy",
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..01a470558 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2265,4 +2265,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert link_header =~ ~r/max_id=#{notification1.id}/
end
end
+
+ test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
+ # Need to set an old-style integer ID to reproduce the problem
+ # (these are no longer assigned to new accounts but were preserved
+ # for existing accounts during the migration to flakeIDs)
+ user_one = insert(:user, %{id: 1212})
+ user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
+
+ resp_one =
+ conn
+ |> get("/api/v1/accounts/#{user_one.id}")
+
+ resp_two =
+ conn
+ |> get("/api/v1/accounts/#{user_two.nickname}")
+
+ resp_three =
+ conn
+ |> get("/api/v1/accounts/#{user_two.id}")
+
+ acc_one = json_response(resp_one, 200)
+ acc_two = json_response(resp_two, 200)
+ acc_three = json_response(resp_three, 200)
+ refute acc_one == acc_two
+ assert acc_two == acc_three
+ end
end
--
cgit v1.2.3
From 20c619f85f7ccd69469eb9977b6f2805edd18525 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Tue, 2 Apr 2019 17:58:32 +0700
Subject: replace `Repo.get_by(User, nickname: nickname)` with
`User.get_by_nickname(nickname)` in tests
---
test/web/twitter_api/twitter_api_controller_test.exs | 2 +-
test/web/twitter_api/twitter_api_test.exs | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 405f0cfae..72b7ea85e 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1021,7 +1021,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
user = json_response(conn, 200)
- fetched_user = Repo.get_by(User, nickname: "lain")
+ fetched_user = User.get_by_nickname("lain")
assert user == UserView.render("show.json", %{user: fetched_user})
end
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index b823bfd68..6c00244de 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -275,7 +275,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = Repo.get_by(User, nickname: "lain")
+ fetched_user = User.get_by_nickname("lain")
assert UserView.render("show.json", %{user: user}) ==
UserView.render("show.json", %{user: fetched_user})
@@ -293,7 +293,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = Repo.get_by(User, nickname: "lain")
+ fetched_user = User.get_by_nickname("lain")
assert UserView.render("show.json", %{user: user}) ==
UserView.render("show.json", %{user: fetched_user})
@@ -369,7 +369,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = Repo.get_by(User, nickname: "vinny")
+ fetched_user = User.get_by_nickname("vinny")
token = Repo.get_by(UserInviteToken, token: token.token)
assert token.used == true
@@ -393,7 +393,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:error, msg} = TwitterAPI.register_user(data)
assert msg == "Invalid token"
- refute Repo.get_by(User, nickname: "GrimReaper")
+ refute User.get_by_nickname("GrimReaper")
end
@moduletag skip: "needs 'registrations_open: false' in config"
@@ -414,7 +414,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:error, msg} = TwitterAPI.register_user(data)
assert msg == "Expired token"
- refute Repo.get_by(User, nickname: "GrimReaper")
+ refute User.get_by_nickname("GrimReaper")
end
test "it returns the error on registration problems" do
@@ -429,7 +429,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:error, error_object} = TwitterAPI.register_user(data)
assert is_binary(error_object[:error])
- refute Repo.get_by(User, nickname: "lain")
+ refute User.get_by_nickname("lain")
end
test "it assigns an integer conversation_id" do
--
cgit v1.2.3
From fdb4357e9ba7a34a603997d50d85593ca2bf6395 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 14:31:18 +0300
Subject: Rename fake param to preview and make the tests check that the object
was not inserted to the db
---
docs/api/differences_in_mastoapi_responses.md | 2 +-
lib/pleroma/web/common_api/common_api.ex | 2 +-
.../web/mastodon_api/mastodon_api_controller_test.exs | 19 +++++++++++++------
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md
index f5ce7493d..7adf29676 100644
--- a/docs/api/differences_in_mastoapi_responses.md
+++ b/docs/api/differences_in_mastoapi_responses.md
@@ -49,4 +49,4 @@ Has these additional fields under the `pleroma` object:
Additional parameters can be added to the JSON body:
-- `fake`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
+- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 8e2937ac5..2f82a32f3 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -180,7 +180,7 @@ defmodule Pleroma.Web.CommonAPI do
object: object,
additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
},
- data["fake"] || false
+ data["preview"] || false
)
res
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 3395c3689..d17d58962 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -154,34 +154,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
"\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
})
+ real_status = json_response(real_conn, 200)
+
+ assert real_status
+ assert Object.get_by_ap_id(real_status["uri"])
+
real_status =
- json_response(real_conn, 200)
+ real_status
|> Map.put("id", nil)
|> Map.put("url", nil)
|> Map.put("uri", nil)
|> Map.put("created_at", nil)
|> Kernel.put_in(["pleroma", "conversation_id"], nil)
- assert real_status
-
fake_conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" =>
"\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
- "fake" => true
+ "preview" => true
})
+ fake_status = json_response(fake_conn, 200)
+
+ assert fake_status
+ refute Object.get_by_ap_id(fake_status["uri"])
+
fake_status =
- json_response(fake_conn, 200)
+ fake_status
|> Map.put("id", nil)
|> Map.put("url", nil)
|> Map.put("uri", nil)
|> Map.put("created_at", nil)
|> Kernel.put_in(["pleroma", "conversation_id"], nil)
- assert fake_status
assert real_status == fake_status
end
--
cgit v1.2.3
From 3465b7ba9ad0e26128f18fd4e36aece767ba269e Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 20:32:37 +0700
Subject: syntax highlighting
---
docs/config/custom_emoji.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md
index 49a451fcc..96fcb2fc6 100644
--- a/docs/config/custom_emoji.md
+++ b/docs/config/custom_emoji.md
@@ -21,7 +21,7 @@ The files should be PNG (APNG is okay with `.png` for `image/png` Content-type)
# Emoji tags (groups)
Default tags are set in `config.exs`.
-```
+```elixir
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
groups: [
@@ -31,7 +31,7 @@ config :pleroma, :emoji,
```
Order of the `groups` matters, so to override default tags just put your group on top of the list. E.g:
-```
+```elixir
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
groups: [
--
cgit v1.2.3
From d140738edf75467420b35c500716cf89de66548d Mon Sep 17 00:00:00 2001
From: Alex S
Date: Tue, 2 Apr 2019 20:35:41 +0700
Subject: second level of headertext change in doc
---
docs/config/custom_emoji.md | 2 +-
lib/pleroma/emoji.ex | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md
index 96fcb2fc6..419a7d0e2 100644
--- a/docs/config/custom_emoji.md
+++ b/docs/config/custom_emoji.md
@@ -18,7 +18,7 @@ foo, /emoji/custom/foo.png
The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon.
-# Emoji tags (groups)
+## Emoji tags (groups)
Default tags are set in `config.exs`.
```elixir
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index 7a60f3961..87c7f2cec 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -214,7 +214,7 @@ defmodule Pleroma.Emoji do
end
@doc """
- Finds a matching group for the given extra filename
+ Finds a matching group for the given emoji filename
"""
@spec match_extra(group_patterns(), String.t()) :: atom() | nil
def match_extra(group_patterns, filename) do
--
cgit v1.2.3
From fd07745d1b18e2a1eeb88a99eaa9d5e728d1aa71 Mon Sep 17 00:00:00 2001
From: lain
Date: Tue, 2 Apr 2019 16:04:18 +0200
Subject: ActivityPub Utils: Greatly speed up the follow / block activity
fetching.
---
lib/pleroma/web/activity_pub/utils.ex | 16 ++++++++++------
test/web/activity_pub/activity_pub_test.exs | 10 ----------
test/web/activity_pub/utils_test.exs | 24 ++++++++++++++++++++++++
3 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 2e9ffe41c..a4b1518de 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -404,13 +404,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do
activity.data
),
where: activity.actor == ^follower_id,
+ # this is to use the index
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
activity.data,
- ^%{object: followed_id}
+ ^followed_id
),
- order_by: [desc: :id],
+ order_by: [fragment("? desc nulls last", activity.id)],
limit: 1
)
@@ -567,13 +569,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do
activity.data
),
where: activity.actor == ^blocker_id,
+ # this is to use the index
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
activity.data,
- ^%{object: blocked_id}
+ ^blocked_id
),
- order_by: [desc: :id],
+ order_by: [fragment("? desc nulls last", activity.id)],
limit: 1
)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index ac5fbe0a9..5ff157e93 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -635,16 +635,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
- describe "fetch the latest Follow" do
- test "fetches the latest Follow activity" do
- %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
- follower = Repo.get_by(User, ap_id: activity.data["actor"])
- followed = Repo.get_by(User, ap_id: activity.data["object"])
-
- assert activity == Utils.fetch_latest_follow(follower, followed)
- end
- end
-
describe "fetching an object" do
test "it fetches an object" do
{:ok, object} =
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index 2bd3ddf93..6b9961d82 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -1,10 +1,34 @@
defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase
+ alias Pleroma.Activity
+ alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ describe "fetch the latest Follow" do
+ test "fetches the latest Follow activity" do
+ %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
+ follower = Repo.get_by(User, ap_id: activity.data["actor"])
+ followed = Repo.get_by(User, ap_id: activity.data["object"])
+
+ assert activity == Utils.fetch_latest_follow(follower, followed)
+ end
+ end
+
+ describe "fetch the latest Block" do
+ test "fetches the latest Block activity" do
+ blocker = insert(:user)
+ blocked = insert(:user)
+ {:ok, activity} = ActivityPub.block(blocker, blocked)
+
+ assert activity == Utils.fetch_latest_block(blocker, blocked)
+ end
+ end
+
describe "determine_explicit_mentions()" do
test "works with an object that has mentions" do
object = %{
--
cgit v1.2.3
From 79cb34a4b0dd1c0ffe45e796f5ac6790e3b31025 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Tue, 2 Apr 2019 23:07:16 +0300
Subject: Fix preview not being usable in form data
---
docs/api/differences_in_mastoapi_responses.md | 2 +-
lib/pleroma/web/common_api/common_api.ex | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md
index 7adf29676..215f43155 100644
--- a/docs/api/differences_in_mastoapi_responses.md
+++ b/docs/api/differences_in_mastoapi_responses.md
@@ -47,6 +47,6 @@ Has these additional fields under the `pleroma` object:
## POST `/api/v1/statuses`
-Additional parameters can be added to the JSON body:
+Additional parameters can be added to the JSON body/Form data:
- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 2f82a32f3..745d1839b 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -180,7 +180,7 @@ defmodule Pleroma.Web.CommonAPI do
object: object,
additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
},
- data["preview"] || false
+ Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
)
res
--
cgit v1.2.3
From d313a0c49c1c42bff60a34b088145e700eb5db53 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Wed, 3 Apr 2019 19:41:15 +0700
Subject: Update `auto_linker` dependency
---
mix.exs | 2 +-
mix.lock | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mix.exs b/mix.exs
index 333f21a91..88da6332a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -93,7 +93,7 @@ defmodule Pleroma.Mixfile do
{:timex, "~> 3.5"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
- ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"},
+ ref: "479dd343f4e563ff91215c8275f3b5c67e032850"},
{:pleroma_job_queue, "~> 0.2.0"}
]
end
diff --git a/mix.lock b/mix.lock
index f401258e9..9c454446a 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,5 +1,5 @@
%{
- "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd", [ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"]},
+ "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "479dd343f4e563ff91215c8275f3b5c67e032850", [ref: "479dd343f4e563ff91215c8275f3b5c67e032850"]},
"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"},
--
cgit v1.2.3
From 86f90c0a54d8f0ee6e6a787e8d28ebc53ff13b05 Mon Sep 17 00:00:00 2001
From: Alex S
Date: Wed, 3 Apr 2019 20:51:09 +0700
Subject: adding indexes to oauth_tokens table
---
priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs
diff --git a/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs b/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs
new file mode 100644
index 000000000..ebcd29389
--- /dev/null
+++ b/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs
@@ -0,0 +1,9 @@
+defmodule Pleroma.Repo.Migrations.AddOauthTokenIndexes do
+ use Ecto.Migration
+
+ def change do
+ create(unique_index(:oauth_tokens, [:token]))
+ create(index(:oauth_tokens, [:app_id]))
+ create(index(:oauth_tokens, [:user_id]))
+ end
+end
--
cgit v1.2.3
From cd41584ac4a90a666f33786d967d37a619c67762 Mon Sep 17 00:00:00 2001
From: Sachin Joshi
Date: Wed, 3 Apr 2019 00:54:16 +0545
Subject: Generate permissive or restrictive robots.txt in the config generator
---
lib/mix/tasks/pleroma/instance.ex | 34 ++++++++++++++++++++++++++++++++++
lib/mix/tasks/pleroma/robots_txt.eex | 2 ++
2 files changed, 36 insertions(+)
create mode 100644 lib/mix/tasks/pleroma/robots_txt.eex
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index 1ba452275..8f8d86a11 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -81,6 +81,14 @@ defmodule Mix.Tasks.Pleroma.Instance do
email = Common.get_option(options, :admin_email, "What is your admin email address?")
+ 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")
@@ -142,6 +150,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
Mix.shell().info("Writing #{psql_path}.")
File.write(psql_path, result_psql)
+ write_robots_txt(indexable)
+
Mix.shell().info(
"\n" <>
"""
@@ -163,4 +173,28 @@ defmodule Mix.Tasks.Pleroma.Instance do
)
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
diff --git a/lib/mix/tasks/pleroma/robots_txt.eex b/lib/mix/tasks/pleroma/robots_txt.eex
new file mode 100644
index 000000000..1af3c47ee
--- /dev/null
+++ b/lib/mix/tasks/pleroma/robots_txt.eex
@@ -0,0 +1,2 @@
+User-Agent: *
+Disallow: <%= if indexable, do: "", else: "/" %>
--
cgit v1.2.3
From af0065a71feb470bd69bec36999bc40a662e3e83 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Thu, 4 Apr 2019 09:07:25 +0200
Subject: mastodon_api_controller.ex: Add pleroma-tan to initial_state
---
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 0de2cca4e..89fd7629a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1121,7 +1121,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
auto_play_gif: false,
display_sensitive_media: false,
reduce_motion: false,
- max_toot_chars: limit
+ max_toot_chars: limit,
+ mascot: "/images/pleroma-fox-tan-smol.png"
},
rights: %{
delete_others_notice: present?(user.info.is_moderator),
--
cgit v1.2.3
From cfa6e7289f5cfdb1fce17eb89bc0513ff624480d Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Thu, 4 Apr 2019 16:10:43 +0700
Subject: Improve Transmogrifier.upgrade_user_from_ap_id/2
---
config/config.exs | 3 ++-
docs/config.md | 6 ++++--
lib/pleroma/web/activity_pub/transmogrifier.ex | 26 ++++++++------------------
test/web/activity_pub/transmogrifier_test.exs | 3 ---
4 files changed, 14 insertions(+), 24 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index dccf7b263..d68edafcb 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -351,7 +351,8 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
config :pleroma_job_queue, :queues,
federator_incoming: 50,
federator_outgoing: 50,
- mailer: 10
+ mailer: 10,
+ transmogrifier: 20
config :pleroma, :fetch_initial_posts,
enabled: false,
diff --git a/docs/config.md b/docs/config.md
index 97a0e6ffa..dd3cc3727 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -200,14 +200,14 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
- `port`
* `url` - a list containing the configuration for generating urls, accepts
- `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
- - `scheme` - e.g `http`, `https`
+ - `scheme` - e.g `http`, `https`
- `port`
- `path`
**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
-Example:
+Example:
```elixir
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "example.com", port: 2020, scheme: "https"],
@@ -296,9 +296,11 @@ curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerando
[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs.
Pleroma has the following queues:
+
* `federator_outgoing` - Outgoing federation
* `federator_incoming` - Incoming federation
* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)
+* `transmogrifier` - Transmogrifier
Example:
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index f733ae7e1..593ae3188 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -954,7 +954,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_tags(object), do: object
- defp user_upgrade_task(user) do
+ def perform(:user_upgrade, user) do
# we pass a fake user so that the followers collection is stripped away
old_follower_address = User.ap_followers(%User{nickname: user.nickname})
@@ -999,28 +999,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Repo.update_all(q, [])
end
- def upgrade_user_from_ap_id(ap_id, async \\ true) do
+ def upgrade_user_from_ap_id(ap_id) do
with %User{local: false} = user <- User.get_by_ap_id(ap_id),
- {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do
- already_ap = User.ap_enabled?(user)
-
- {:ok, user} =
- User.upgrade_changeset(user, data)
- |> Repo.update()
-
- if !already_ap do
- # This could potentially take a long time, do it in the background
- if async do
- Task.start(fn ->
- user_upgrade_task(user)
- end)
- else
- user_upgrade_task(user)
- end
+ {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
+ already_ap <- User.ap_enabled?(user),
+ {:ok, user} <- user |> User.upgrade_changeset(data) |> User.update_and_set_cache() do
+ unless already_ap do
+ PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user])
end
{:ok, user}
else
+ %User{} = user -> {:ok, user}
e -> e
end
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 62b973c4f..47cffe257 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -1028,9 +1028,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert user.info.note_count == 1
assert user.follower_address == "https://niu.moe/users/rye/followers"
- # Wait for the background task
- :timer.sleep(1000)
-
user = User.get_by_id(user.id)
assert user.info.note_count == 1
--
cgit v1.2.3
From b655a8ea839d19443f44ff5b300a069d88ec7d58 Mon Sep 17 00:00:00 2001
From: href
Date: Wed, 6 Feb 2019 10:33:05 +0100
Subject: Add recon
---
mix.exs | 9 ++++++++-
mix.lock | 8 ++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/mix.exs b/mix.exs
index 88da6332a..8cb389248 100644
--- a/mix.exs
+++ b/mix.exs
@@ -94,7 +94,14 @@ defmodule Pleroma.Mixfile do
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
ref: "479dd343f4e563ff91215c8275f3b5c67e032850"},
- {:pleroma_job_queue, "~> 0.2.0"}
+ {:pleroma_job_queue, "~> 0.2.0"},
+ {:telemetry, "~> 0.3"},
+ {:prometheus_ex, "~> 3.0"},
+ {:prometheus_plugs, "~> 1.1"},
+ {:prometheus_phoenix, "~> 1.2"},
+ {:prometheus_ecto, "~> 1.4"},
+ {:prometheus_process_collector, "~> 1.4"},
+ {:recon, github: "ferd/recon"}
]
end
diff --git a/mix.lock b/mix.lock
index 9c454446a..0ece4b353 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,4 +1,5 @@
%{
+ "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm"},
"auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "479dd343f4e563ff91215c8275f3b5c67e032850", [ref: "479dd343f4e563ff91215c8275f3b5c67e032850"]},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
@@ -57,7 +58,14 @@
"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"},
+ "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"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
+ "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", []},
"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"},
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
--
cgit v1.2.3
From bc3618a38d2e37254e27f723d3dd61679eca9be5 Mon Sep 17 00:00:00 2001
From: href
Date: Wed, 30 Jan 2019 16:32:30 +0100
Subject: Set up telemetry and prometheus
---
config/config.exs | 5 +++++
lib/pleroma/application.ex | 8 ++++++++
lib/pleroma/repo.ex | 4 ++++
lib/pleroma/web/endpoint.ex | 20 ++++++++++++++++++++
4 files changed, 37 insertions(+)
diff --git a/config/config.exs b/config/config.exs
index dccf7b263..1e086f44c 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -8,6 +8,10 @@ use Mix.Config
# General application configuration
config :pleroma, ecto_repos: [Pleroma.Repo]
+config :pleroma, Pleroma.Repo,
+ types: Pleroma.PostgresTypes,
+ loggers: [Pleroma.Repo.Instrumenter, Ecto.LogEntry]
+
config :pleroma, Pleroma.Captcha,
enabled: false,
seconds_valid: 60,
@@ -87,6 +91,7 @@ websocket_config = [
# Configures the endpoint
config :pleroma, Pleroma.Web.Endpoint,
+ instrumenters: [Pleroma.Web.Endpoint.Instrumenter],
url: [host: "localhost"],
http: [
dispatch: [
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 782d1d589..03dcbab1a 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -25,6 +25,7 @@ defmodule Pleroma.Application do
import Cachex.Spec
Pleroma.Config.DeprecationWarnings.warn()
+ setup_instrumenters()
# Define workers and child supervisors to be supervised
children =
@@ -140,6 +141,13 @@ defmodule Pleroma.Application do
end
end
+ defp setup_instrumenters() do
+ Pleroma.Web.Endpoint.MetricsExporter.setup()
+ Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
+ Pleroma.Web.Endpoint.Instrumenter.setup()
+ Pleroma.Repo.Instrumenter.setup()
+ end
+
if Mix.env() == :test do
defp streamer_child, do: []
defp chat_child, do: []
diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex
index 4af1bde56..aa5d427ae 100644
--- a/lib/pleroma/repo.ex
+++ b/lib/pleroma/repo.ex
@@ -8,6 +8,10 @@ defmodule Pleroma.Repo do
adapter: Ecto.Adapters.Postgres,
migration_timestamps: [type: :naive_datetime_usec]
+ defmodule Instrumenter do
+ use Prometheus.EctoInstrumenter
+ end
+
@doc """
Dynamically loads the repository url from the
DATABASE_URL environment variable.
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index fa2d1cbe7..6d9528c86 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -70,6 +70,26 @@ defmodule Pleroma.Web.Endpoint do
extra: "SameSite=Strict"
)
+ # Note: the plug and its configuration is compile-time this can't be upstreamed yet
+ if proxies = Pleroma.Config.get([__MODULE__, :reverse_proxies]) do
+ plug(RemoteIp, proxies: proxies)
+ end
+
+ defmodule Instrumenter do
+ use Prometheus.PhoenixInstrumenter
+ end
+
+ defmodule PipelineInstrumenter do
+ use Prometheus.PlugPipelineInstrumenter
+ end
+
+ defmodule MetricsExporter do
+ use Prometheus.PlugExporter
+ end
+
+ plug(PipelineInstrumenter)
+ plug(MetricsExporter)
+
plug(Pleroma.Web.Router)
@doc """
--
cgit v1.2.3
From 0b5c818cb78b8c23fb2ba7ef372d0688ea9f36b7 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Mon, 25 Mar 2019 15:29:04 +0700
Subject: [#1] fix telemetry
---
config/config.exs | 2 +-
lib/pleroma/application.ex | 25 ++++++++++++++++++-------
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 1e086f44c..4fd63f99d 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -10,7 +10,7 @@ config :pleroma, ecto_repos: [Pleroma.Repo]
config :pleroma, Pleroma.Repo,
types: Pleroma.PostgresTypes,
- loggers: [Pleroma.Repo.Instrumenter, Ecto.LogEntry]
+ telemetry_event: [Pleroma.Repo.Instrumenter]
config :pleroma, Pleroma.Captcha,
enabled: false,
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 03dcbab1a..c3f3126c6 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -127,6 +127,24 @@ defmodule Pleroma.Application do
Supervisor.start_link(children, opts)
end
+ defp setup_instrumenters() do
+ require Prometheus.Registry
+
+ :ok =
+ :telemetry.attach(
+ "prometheus-ecto",
+ [:pleroma, :repo, :query],
+ &Pleroma.Repo.Instrumenter.handle_event/4,
+ %{}
+ )
+
+ Prometheus.Registry.register_collector(:prometheus_process_collector)
+ Pleroma.Web.Endpoint.MetricsExporter.setup()
+ Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
+ Pleroma.Web.Endpoint.Instrumenter.setup()
+ Pleroma.Repo.Instrumenter.setup()
+ end
+
def enabled_hackney_pools do
[:media] ++
if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
@@ -141,13 +159,6 @@ defmodule Pleroma.Application do
end
end
- defp setup_instrumenters() do
- Pleroma.Web.Endpoint.MetricsExporter.setup()
- Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
- Pleroma.Web.Endpoint.Instrumenter.setup()
- Pleroma.Repo.Instrumenter.setup()
- end
-
if Mix.env() == :test do
defp streamer_child, do: []
defp chat_child, do: []
--
cgit v1.2.3
From 5564cd421dfc706208df0b7447b0d692dffe052e Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Thu, 4 Apr 2019 12:19:31 -0500
Subject: Document Prometheus
---
docs/api/prometheus.md | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 docs/api/prometheus.md
diff --git a/docs/api/prometheus.md b/docs/api/prometheus.md
new file mode 100644
index 000000000..19c564e3c
--- /dev/null
+++ b/docs/api/prometheus.md
@@ -0,0 +1,22 @@
+# Prometheus Metrics
+
+Pleroma includes support for exporting metrics via the [prometheus_ex](https://github.com/deadtrickster/prometheus.ex) library.
+
+## `/api/pleroma/app_metrics`
+### Exports Prometheus application metrics
+* Method: `GET`
+* Authentication: not required
+* Params: none
+* Response: JSON
+
+## Grafana
+### Config example
+The following is a config example to use with [Grafana](https://grafana.com)
+
+```
+ - job_name: 'beam'
+ metrics_path: /api/pleroma/app_metrics
+ scheme: https
+ static_configs:
+ - targets: ['pleroma.soykaf.com']
+```
--
cgit v1.2.3
From 7e930559fece1a86891645333cc79a18f440ef1d Mon Sep 17 00:00:00 2001
From: href
Date: Wed, 30 Jan 2019 16:44:38 +0100
Subject: Serve metrics at `/api/pleroma/app_metrics`
---
config/config.exs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/config/config.exs b/config/config.exs
index 4fd63f99d..ebaf1aec5 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -353,6 +353,7 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
initial_timeout: 30,
max_retries: 5
+<<<<<<< HEAD
config :pleroma_job_queue, :queues,
federator_incoming: 50,
federator_outgoing: 50,
@@ -385,6 +386,8 @@ config :pleroma, :ldap,
config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Sendmail
+config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
+
# 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"
--
cgit v1.2.3
From 7222afe01b13586018b481172731309587191338 Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Thu, 4 Apr 2019 12:29:10 -0500
Subject: Clean merge crumbs
---
config/config.exs | 1 -
1 file changed, 1 deletion(-)
diff --git a/config/config.exs b/config/config.exs
index ebaf1aec5..b19b36b22 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -353,7 +353,6 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
initial_timeout: 30,
max_retries: 5
-<<<<<<< HEAD
config :pleroma_job_queue, :queues,
federator_incoming: 50,
federator_outgoing: 50,
--
cgit v1.2.3
From 69038887b2930072356aa00841b889c59518e264 Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Thu, 4 Apr 2019 12:36:57 -0500
Subject: Code readability tweak
---
lib/pleroma/application.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index c3f3126c6..1fc3fb728 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -127,7 +127,7 @@ defmodule Pleroma.Application do
Supervisor.start_link(children, opts)
end
- defp setup_instrumenters() do
+ defp setup_instrumenters do
require Prometheus.Registry
:ok =
--
cgit v1.2.3
From f7cd9131d4aa0da3c4c0174acc56ce1bbdbd284c Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Thu, 4 Apr 2019 22:41:03 +0300
Subject: [#923] OAuth consumer controller tests. Misc. improvements.
---
lib/pleroma/web/oauth/oauth_controller.ex | 4 +
.../web/templates/o_auth/o_auth/register.html.eex | 1 +
.../web/templates/o_auth/o_auth/show.html.eex | 2 +-
test/support/factory.ex | 16 +
test/web/oauth/oauth_controller_test.exs | 327 ++++++++++++++++++++-
5 files changed, 343 insertions(+), 7 deletions(-)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 1b467e983..2dcaaabc1 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -253,6 +253,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
auth_params = %{
"client_id" => params["client_id"],
"redirect_uri" => params["redirect_uri"],
+ "state" => params["state"],
"scopes" => oauth_scopes(params, nil)
}
@@ -289,6 +290,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
render(conn, "register.html", %{
client_id: params["client_id"],
redirect_uri: params["redirect_uri"],
+ state: params["state"],
scopes: oauth_scopes(params, []),
nickname: params["nickname"],
email: params["email"]
@@ -313,6 +315,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
)
else
_ ->
+ params = Map.delete(params, "password")
+
conn
|> put_flash(:error, "Unknown error, please try again.")
|> redirect(to: o_auth_path(conn, :registration_details, params))
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
index f4547170c..2e806e5fb 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
@@ -44,5 +44,6 @@ please provide the details below.
<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
<%= hidden_input f, :scope, value: Enum.join(@scopes, " ") %>
+<%= hidden_input f, :state, value: @state %>
<% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index e6cf1db45..0144675ab 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -22,7 +22,7 @@
<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :response_type, value: @response_type %>
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
-<%= hidden_input f, :state, value: @state%>
+<%= hidden_input f, :state, value: @state %>
<%= submit "Authorize" %>
<% end %>
diff --git a/test/support/factory.ex b/test/support/factory.ex
index e1a08315a..67953931b 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -257,4 +257,20 @@ defmodule Pleroma.Factory do
user: build(:user)
}
end
+
+ def registration_factory do
+ user = insert(:user)
+
+ %Pleroma.Registration{
+ user: user,
+ provider: "twitter",
+ uid: "171799000",
+ info: %{
+ "name" => "John Doe",
+ "email" => "john@doe.com",
+ "nickname" => "johndoe",
+ "description" => "My bio"
+ }
+ }
+ end
end
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index a9a0b9ed4..e13f4700d 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -5,24 +5,339 @@
defmodule Pleroma.Web.OAuth.OAuthControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
+ import Mock
+ alias Pleroma.Registration
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- describe "GET /oauth/authorize" do
+ @session_opts [
+ store: :cookie,
+ key: "_test",
+ signing_salt: "cooldude"
+ ]
+
+ describe "in OAuth consumer mode, " do
setup do
- session_opts = [
- store: :cookie,
- key: "_test",
- signing_salt: "cooldude"
+ oauth_consumer_enabled_path = [:auth, :oauth_consumer_enabled]
+ oauth_consumer_strategies_path = [:auth, :oauth_consumer_strategies]
+ oauth_consumer_enabled = Pleroma.Config.get(oauth_consumer_enabled_path)
+ oauth_consumer_strategies = Pleroma.Config.get(oauth_consumer_strategies_path)
+
+ Pleroma.Config.put(oauth_consumer_enabled_path, true)
+ Pleroma.Config.put(oauth_consumer_strategies_path, ~w(twitter facebook))
+
+ on_exit(fn ->
+ Pleroma.Config.put(oauth_consumer_enabled_path, oauth_consumer_enabled)
+ Pleroma.Config.put(oauth_consumer_strategies_path, oauth_consumer_strategies)
+ end)
+
+ [
+ app: insert(:oauth_app),
+ conn:
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session()
]
+ end
+
+ test "GET /oauth/authorize also renders OAuth consumer form", %{
+ app: app,
+ conn: conn
+ } do
+ conn =
+ get(
+ conn,
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read"
+ }
+ )
+
+ assert response = html_response(conn, 200)
+ assert response =~ "Sign in with Twitter"
+ assert response =~ o_auth_path(conn, :prepare_request)
+ end
+
+ test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %{
+ app: app,
+ conn: conn
+ } do
+ conn =
+ get(
+ conn,
+ "/oauth/prepare_request",
+ %{
+ "provider" => "twitter",
+ "scope" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state"
+ }
+ )
+
+ assert response = html_response(conn, 302)
+ redirected_to = redirected_to(conn)
+ [state] = Regex.run(~r/(?<=state=).*?(?=\Z|&)/, redirected_to)
+ state = URI.decode(state)
+ assert {:ok, state_params} = Poison.decode(state)
+
+ expected_scope_param = Enum.join(app.scopes, "+")
+ expected_client_id_param = app.client_id
+ expected_redirect_uri_param = app.redirect_uris
+
+ assert %{
+ "scope" => ^expected_scope_param,
+ "client_id" => ^expected_client_id_param,
+ "redirect_uri" => ^expected_redirect_uri_param,
+ "state" => "a_state"
+ } = state_params
+ end
+
+ test "on authentication error, redirects to `redirect_uri`", %{app: app, conn: conn} do
+ state_params = %{
+ "scope" => Enum.join(app.scopes, " "),
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => ""
+ }
+
+ conn =
+ conn
+ |> assign(:ueberauth_failure, %{errors: [%{message: "unknown error"}]})
+ |> get(
+ "/oauth/twitter/callback",
+ %{
+ "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+ "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+ "provider" => "twitter",
+ "state" => Poison.encode!(state_params)
+ }
+ )
+
+ assert response = html_response(conn, 302)
+ assert redirected_to(conn) == app.redirect_uris
+ end
+
+ test "with user-bound registration, GET /oauth//callback redirects to `redirect_uri` with `code`",
+ %{app: app, conn: conn} do
+ registration = insert(:registration)
+
+ state_params = %{
+ "scope" => Enum.join(app.scopes, " "),
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => ""
+ }
+
+ with_mock Pleroma.Web.Auth.Authenticator,
+ get_registration: fn _, _ -> {:ok, registration} end do
+ conn =
+ get(
+ conn,
+ "/oauth/twitter/callback",
+ %{
+ "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+ "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+ "provider" => "twitter",
+ "state" => Poison.encode!(state_params)
+ }
+ )
+
+ assert response = html_response(conn, 302)
+ assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ end
+ end
+
+ test "with user-unbound registration, GET /oauth//callback redirects to registration_details page",
+ %{app: app, conn: conn} do
+ registration = insert(:registration, user: nil)
+
+ state_params = %{
+ "scope" => "read",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state"
+ }
+
+ with_mock Pleroma.Web.Auth.Authenticator,
+ get_registration: fn _, _ -> {:ok, registration} end do
+ conn =
+ get(
+ conn,
+ "/oauth/twitter/callback",
+ %{
+ "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+ "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+ "provider" => "twitter",
+ "state" => Poison.encode!(state_params)
+ }
+ )
+
+ expected_redirect_params =
+ state_params
+ |> Map.delete("scope")
+ |> Map.merge(%{
+ "scopes" => ["read"],
+ "email" => Registration.email(registration),
+ "nickname" => Registration.nickname(registration)
+ })
+
+ assert response = html_response(conn, 302)
+
+ assert redirected_to(conn) ==
+ o_auth_path(conn, :registration_details, expected_redirect_params)
+ end
+ end
+
+ test "GET /oauth/registration_details renders registration details form", %{
+ app: app,
+ conn: conn
+ } do
+ conn =
+ get(
+ conn,
+ "/oauth/registration_details",
+ %{
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state",
+ "nickname" => nil,
+ "email" => "john@doe.com"
+ }
+ )
+
+ assert response = html_response(conn, 200)
+ assert response =~ ~r/name="op" type="submit" value="register"/
+ assert response =~ ~r/name="op" type="submit" value="connect"/
+ end
+
+ test "with valid params, POST /oauth/register?op=register redirects to `redirect_uri` with `code`",
+ %{
+ app: app,
+ conn: conn
+ } do
+ registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post(
+ "/oauth/register",
+ %{
+ "op" => "register",
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state",
+ "nickname" => "availablenick",
+ "email" => "available@email.com"
+ }
+ )
+
+ assert response = html_response(conn, 302)
+ assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ end
+
+ test "with invalid params, POST /oauth/register?op=register redirects to registration_details page",
+ %{
+ app: app,
+ conn: conn
+ } do
+ another_user = insert(:user)
+ registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
+
+ params = %{
+ "op" => "register",
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state",
+ "nickname" => another_user.nickname,
+ "email" => another_user.email
+ }
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post("/oauth/register", params)
+
+ assert response = html_response(conn, 302)
+
+ assert redirected_to(conn) ==
+ o_auth_path(conn, :registration_details, params)
+ end
+
+ test "with valid params, POST /oauth/register?op=connect redirects to `redirect_uri` with `code`",
+ %{
+ app: app,
+ conn: conn
+ } do
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
+ registration = insert(:registration, user: nil)
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post(
+ "/oauth/register",
+ %{
+ "op" => "connect",
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state",
+ "auth_name" => user.nickname,
+ "password" => "testpassword"
+ }
+ )
+ assert response = html_response(conn, 302)
+ assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
+ end
+
+ test "with invalid params, POST /oauth/register?op=connect redirects to registration_details page",
+ %{
+ app: app,
+ conn: conn
+ } do
+ user = insert(:user)
+ registration = insert(:registration, user: nil)
+
+ params = %{
+ "op" => "connect",
+ "scopes" => app.scopes,
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "a_state",
+ "auth_name" => user.nickname,
+ "password" => "wrong password"
+ }
+
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post("/oauth/register", params)
+
+ assert response = html_response(conn, 302)
+
+ assert redirected_to(conn) ==
+ o_auth_path(conn, :registration_details, Map.delete(params, "password"))
+ end
+ end
+
+ describe "GET /oauth/authorize" do
+ setup do
[
app: insert(:oauth_app, redirect_uris: "https://redirect.url"),
conn:
build_conn()
- |> Plug.Session.call(Plug.Session.init(session_opts))
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
|> fetch_session()
]
end
--
cgit v1.2.3
From 3b12eeda192e739e8328ef4202059bb482d1cff2 Mon Sep 17 00:00:00 2001
From: feld
Date: Thu, 4 Apr 2019 19:52:22 +0000
Subject: Add ability to ship logs to a Slack channel
---
config/config.exs | 5 +++++
docs/config.md | 20 +++++++++++++++++++-
mix.exs | 5 +++--
mix.lock | 1 +
4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index dccf7b263..c143f79fc 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -118,6 +118,11 @@ config :logger, :ex_syslogger,
format: "$metadata[$level] $message",
metadata: [:request_id]
+config :quack,
+ level: :warn,
+ meta: [:all],
+ webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
+
config :mime, :types, %{
"application/xml" => ["xml"],
"application/xrd+xml" => ["xrd+xml"],
diff --git a/docs/config.md b/docs/config.md
index 97a0e6ffa..06d6fd757 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -105,7 +105,7 @@ config :pleroma, Pleroma.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`)
## :logger
-* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog
+* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog, and `Quack.Logger` to log to Slack
An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed:
```
@@ -128,6 +128,24 @@ config :logger, :ex_syslogger,
See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_syslogger’s documentation](https://hexdocs.pm/ex_syslogger/)
+An example of logging info to local syslog, but warn to a Slack channel:
+```
+config :logger,
+ backends: [ {ExSyslogger, :ex_syslogger}, Quack.Logger ],
+ level: :info
+
+config :logger, :ex_syslogger,
+ level: :info,
+ ident: "pleroma",
+ format: "$metadata[$level] $message"
+
+config :quack,
+ level: :warn,
+ meta: [:all],
+ webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE"
+```
+
+See the [Quack Github](https://github.com/azohra/quack) for more details
## :frontend_configurations
diff --git a/mix.exs b/mix.exs
index 88da6332a..3a04e0060 100644
--- a/mix.exs
+++ b/mix.exs
@@ -41,7 +41,7 @@ defmodule Pleroma.Mixfile do
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin],
+ extra_applications: [:logger, :runtime_tools, :comeonin, :quack],
included_applications: [:ex_syslogger]
]
end
@@ -94,7 +94,8 @@ defmodule Pleroma.Mixfile do
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
ref: "479dd343f4e563ff91215c8275f3b5c67e032850"},
- {:pleroma_job_queue, "~> 0.2.0"}
+ {:pleroma_job_queue, "~> 0.2.0"},
+ {:quack, "~> 0.1.1"}
]
end
diff --git a/mix.lock b/mix.lock
index 9c454446a..d84d11049 100644
--- a/mix.lock
+++ b/mix.lock
@@ -57,6 +57,7 @@
"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"},
+ "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"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"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"},
--
cgit v1.2.3
From 3e7f2bfc2f4769af3cedea3126fa0b3cab3f2b7b Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Fri, 5 Apr 2019 09:19:17 +0300
Subject: [#923] OAuthController#callback adjustments (with tests).
---
lib/pleroma/web/oauth/oauth_controller.ex | 8 +-------
test/web/oauth/oauth_controller_test.exs | 27 +++++++++++++--------------
2 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 2dcaaabc1..404728899 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -249,13 +249,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
with {:ok, registration} <- Authenticator.get_registration(conn, params) do
user = Repo.preload(registration, :user).user
-
- auth_params = %{
- "client_id" => params["client_id"],
- "redirect_uri" => params["redirect_uri"],
- "state" => params["state"],
- "scopes" => oauth_scopes(params, nil)
- }
+ auth_params = Map.take(params, ~w(client_id redirect_uri scope scopes state))
if user do
create_authorization(
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index e13f4700d..75333f2d5 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -73,7 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"/oauth/prepare_request",
%{
"provider" => "twitter",
- "scope" => app.scopes,
+ "scope" => "read follow",
"client_id" => app.client_id,
"redirect_uri" => app.redirect_uris,
"state" => "a_state"
@@ -81,21 +81,20 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
)
assert response = html_response(conn, 302)
- redirected_to = redirected_to(conn)
- [state] = Regex.run(~r/(?<=state=).*?(?=\Z|&)/, redirected_to)
- state = URI.decode(state)
- assert {:ok, state_params} = Poison.decode(state)
- expected_scope_param = Enum.join(app.scopes, "+")
- expected_client_id_param = app.client_id
- expected_redirect_uri_param = app.redirect_uris
+ redirect_query = URI.parse(redirected_to(conn)).query
+ assert %{"state" => state_param} = URI.decode_query(redirect_query)
+ assert {:ok, state_components} = Poison.decode(state_param)
+
+ expected_client_id = app.client_id
+ expected_redirect_uri = app.redirect_uris
assert %{
- "scope" => ^expected_scope_param,
- "client_id" => ^expected_client_id_param,
- "redirect_uri" => ^expected_redirect_uri_param,
+ "scope" => "read follow",
+ "client_id" => ^expected_client_id,
+ "redirect_uri" => ^expected_redirect_uri,
"state" => "a_state"
- } = state_params
+ } = state_components
end
test "on authentication error, redirects to `redirect_uri`", %{app: app, conn: conn} do
@@ -158,7 +157,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
registration = insert(:registration, user: nil)
state_params = %{
- "scope" => "read",
+ "scope" => "read write",
"client_id" => app.client_id,
"redirect_uri" => app.redirect_uris,
"state" => "a_state"
@@ -182,7 +181,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
state_params
|> Map.delete("scope")
|> Map.merge(%{
- "scopes" => ["read"],
+ "scope" => "read write",
"email" => Registration.email(registration),
"nickname" => Registration.nickname(registration)
})
--
cgit v1.2.3
From 47a236f7537ad4366d07361d184c84f3912648f1 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Fri, 5 Apr 2019 15:12:02 +0300
Subject: [#923] OAuth consumer mode refactoring, new tests, tests adjustments,
readme.
---
config/config.exs | 4 +-
docs/config.md | 55 +++++++++
lib/pleroma/config.ex | 4 +
lib/pleroma/web/endpoint.ex | 2 +-
lib/pleroma/web/oauth/fallback_controller.ex | 17 ++-
lib/pleroma/web/oauth/oauth_controller.ex | 130 +++++++++++----------
.../web/templates/o_auth/o_auth/consumer.html.eex | 2 +-
.../web/templates/o_auth/o_auth/show.html.eex | 2 +-
test/registration_test.exs | 59 ++++++++++
test/web/oauth/oauth_controller_test.exs | 110 ++++++++---------
10 files changed, 254 insertions(+), 131 deletions(-)
create mode 100644 test/registration_test.exs
diff --git a/config/config.exs b/config/config.exs
index 9bc79f939..05b164273 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -397,9 +397,7 @@ config :ueberauth,
base_path: "/oauth",
providers: ueberauth_providers
-config :pleroma, :auth,
- oauth_consumer_strategies: oauth_consumer_strategies,
- oauth_consumer_enabled: oauth_consumer_strategies != []
+config :pleroma, :auth, oauth_consumer_strategies: oauth_consumer_strategies
config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Sendmail
diff --git a/docs/config.md b/docs/config.md
index 06d6fd757..36d7f1273 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -412,3 +412,58 @@ Pleroma account will be created with the same name as the LDAP user name.
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
+
+## :auth
+
+Authentication / authorization settings.
+
+* `oauth_consumer_strategies`: lists enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable.
+
+OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.).
+Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies).
+
+Note: each strategy is shipped as a separate dependency; in order to get the strategies, run `OAUTH_CONSUMER_STRATEGIES="..." mix deps.get`,
+e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`.
+The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies.
+
+Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies.
+
+* For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback
+
+* For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https:///oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps//fb-login/settings/
+
+* For Google, [register an app](https://console.developers.google.com), configure callback URL to https:///oauth/google/callback
+
+* For Microsoft, [register an app](https://portal.azure.com), configure callback URL to https:///oauth/microsoft/callback
+
+Once the app is configured on external OAuth provider side, add app's credentials and strategy-specific settings (if any — e.g. see Microsoft below) to `config/prod.secret.exs`,
+per strategy's documentation (e.g. [ueberauth_twitter](https://github.com/ueberauth/ueberauth_twitter)). Example config basing on environment variables:
+
+```
+# Twitter
+config :ueberauth, Ueberauth.Strategy.Twitter.OAuth,
+ consumer_key: System.get_env("TWITTER_CONSUMER_KEY"),
+ consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET")
+
+# Facebook
+config :ueberauth, Ueberauth.Strategy.Facebook.OAuth,
+ client_id: System.get_env("FACEBOOK_APP_ID"),
+ client_secret: System.get_env("FACEBOOK_APP_SECRET"),
+ redirect_uri: System.get_env("FACEBOOK_REDIRECT_URI")
+
+# Google
+config :ueberauth, Ueberauth.Strategy.Google.OAuth,
+ client_id: System.get_env("GOOGLE_CLIENT_ID"),
+ client_secret: System.get_env("GOOGLE_CLIENT_SECRET"),
+ redirect_uri: System.get_env("GOOGLE_REDIRECT_URI")
+
+# Microsoft
+config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth,
+ client_id: System.get_env("MICROSOFT_CLIENT_ID"),
+ client_secret: System.get_env("MICROSOFT_CLIENT_SECRET")
+
+config :ueberauth, Ueberauth,
+ providers: [
+ microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]}
+ ]
+```
diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex
index 21507cd38..189faa15f 100644
--- a/lib/pleroma/config.ex
+++ b/lib/pleroma/config.ex
@@ -57,4 +57,8 @@ defmodule Pleroma.Config do
def delete(key) do
Application.delete_env(:pleroma, key)
end
+
+ def oauth_consumer_strategies, do: get([:auth, :oauth_consumer_strategies], [])
+
+ def oauth_consumer_enabled?, do: oauth_consumer_strategies() != []
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index b85b95bf9..085f23159 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -59,7 +59,7 @@ defmodule Pleroma.Web.Endpoint do
else: "pleroma_key"
same_site =
- if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do
+ if Pleroma.Config.oauth_consumer_enabled?() do
# Note: "SameSite=Strict" prevents sign in with external OAuth provider
# (there would be no cookies during callback request from OAuth provider)
"SameSite=Lax"
diff --git a/lib/pleroma/web/oauth/fallback_controller.ex b/lib/pleroma/web/oauth/fallback_controller.ex
index f0fe3b578..afaa00242 100644
--- a/lib/pleroma/web/oauth/fallback_controller.ex
+++ b/lib/pleroma/web/oauth/fallback_controller.ex
@@ -6,8 +6,21 @@ defmodule Pleroma.Web.OAuth.FallbackController do
use Pleroma.Web, :controller
alias Pleroma.Web.OAuth.OAuthController
- # No user/password
- def call(conn, _) do
+ def call(conn, {:register, :generic_error}) do
+ conn
+ |> put_status(:internal_server_error)
+ |> put_flash(:error, "Unknown error, please check the details and try again.")
+ |> OAuthController.registration_details(conn.params)
+ end
+
+ def call(conn, {:register, _error}) do
+ conn
+ |> put_status(:unauthorized)
+ |> put_flash(:error, "Invalid Username/Password")
+ |> OAuthController.registration_details(conn.params)
+ end
+
+ def call(conn, _error) do
conn
|> put_status(:unauthorized)
|> put_flash(:error, "Invalid Username/Password")
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 404728899..108303eb2 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
- if Pleroma.Config.get([:auth, :oauth_consumer_enabled]), do: plug(Ueberauth)
+ if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth)
plug(:fetch_session)
plug(:fetch_flash)
@@ -62,60 +62,65 @@ defmodule Pleroma.Web.OAuth.OAuthController do
def create_authorization(
conn,
- %{
- "authorization" => %{"redirect_uri" => redirect_uri} = auth_params
- } = params,
+ %{"authorization" => auth_params} = params,
opts \\ []
) do
- with {:ok, auth} <-
- (opts[:auth] && {:ok, opts[:auth]}) ||
- do_create_authorization(conn, params, opts[:user]) do
- redirect_uri = redirect_uri(conn, redirect_uri)
-
- cond do
- redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
- render(conn, "results.html", %{
- auth: auth
- })
-
- true ->
- connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?"
- url = "#{redirect_uri}#{connector}"
- url_params = %{:code => auth.token}
-
- url_params =
- if auth_params["state"] do
- Map.put(url_params, :state, auth_params["state"])
- else
- url_params
- end
+ with {:ok, auth} <- do_create_authorization(conn, params, opts[:user]) do
+ after_create_authorization(conn, auth, auth_params)
+ else
+ error ->
+ handle_create_authorization_error(conn, error, auth_params)
+ end
+ end
- url = "#{url}#{Plug.Conn.Query.encode(url_params)}"
+ def after_create_authorization(conn, auth, %{"redirect_uri" => redirect_uri} = auth_params) do
+ redirect_uri = redirect_uri(conn, redirect_uri)
- redirect(conn, external: url)
- end
+ if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do
+ render(conn, "results.html", %{
+ auth: auth
+ })
else
- {scopes_issue, _} when scopes_issue in [:unsupported_scopes, :missing_scopes] ->
- # Per https://github.com/tootsuite/mastodon/blob/
- # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
- conn
- |> put_flash(:error, "This action is outside the authorized scopes")
- |> put_status(:unauthorized)
- |> authorize(auth_params)
+ connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?"
+ url = "#{redirect_uri}#{connector}"
+ url_params = %{:code => auth.token}
- {:auth_active, false} ->
- # Per https://github.com/tootsuite/mastodon/blob/
- # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
- conn
- |> put_flash(:error, "Your login is missing a confirmed e-mail address")
- |> put_status(:forbidden)
- |> authorize(auth_params)
+ url_params =
+ if auth_params["state"] do
+ Map.put(url_params, :state, auth_params["state"])
+ else
+ url_params
+ end
- error ->
- Authenticator.handle_error(conn, error)
+ url = "#{url}#{Plug.Conn.Query.encode(url_params)}"
+
+ redirect(conn, external: url)
end
end
+ defp handle_create_authorization_error(conn, {scopes_issue, _}, auth_params)
+ when scopes_issue in [:unsupported_scopes, :missing_scopes] do
+ # Per https://github.com/tootsuite/mastodon/blob/
+ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
+ conn
+ |> put_flash(:error, "This action is outside the authorized scopes")
+ |> put_status(:unauthorized)
+ |> authorize(auth_params)
+ end
+
+ defp handle_create_authorization_error(conn, {:auth_active, false}, auth_params) do
+ # Per https://github.com/tootsuite/mastodon/blob/
+ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
+ conn
+ |> put_flash(:error, "Your login is missing a confirmed e-mail address")
+ |> put_status(:forbidden)
+ |> authorize(auth_params)
+ end
+
+ defp handle_create_authorization_error(conn, error, _auth_params) do
+ Authenticator.handle_error(conn, error)
+ end
+
def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
with %App{} = app <- get_app_from_request(conn, params),
fixed_token = fix_padding(params["code"]),
@@ -202,6 +207,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
+ @doc "Prepares OAuth request to provider for Ueberauth"
def prepare_request(conn, %{"provider" => provider} = params) do
scope =
oauth_scopes(params, [])
@@ -218,6 +224,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|> Map.drop(~w(scope scopes client_id redirect_uri))
|> Map.put("state", state)
+ # Handing the request to Ueberauth
redirect(conn, to: o_auth_path(conn, :request, provider, params))
end
@@ -266,7 +273,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
conn
|> put_session(:registration_id, registration.id)
- |> redirect(to: o_auth_path(conn, :registration_details, registration_params))
+ |> registration_details(registration_params)
end
else
_ ->
@@ -292,32 +299,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
def register(conn, %{"op" => "connect"} = params) do
- create_authorization_params = %{
- "authorization" => Map.merge(params, %{"name" => params["auth_name"]})
- }
+ authorization_params = Map.put(params, "name", params["auth_name"])
+ create_authorization_params = %{"authorization" => authorization_params}
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
%Registration{} = registration <- Repo.get(Registration, registration_id),
- {:ok, auth} <- do_create_authorization(conn, create_authorization_params),
+ {_, {:ok, auth}} <-
+ {:create_authorization, do_create_authorization(conn, create_authorization_params)},
%User{} = user <- Repo.preload(auth, :user).user,
{:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
conn
|> put_session_registration_id(nil)
- |> create_authorization(
- create_authorization_params,
- auth: auth
- )
+ |> after_create_authorization(auth, authorization_params)
else
- _ ->
- params = Map.delete(params, "password")
+ {:create_authorization, error} ->
+ {:register, handle_create_authorization_error(conn, error, create_authorization_params)}
- conn
- |> put_flash(:error, "Unknown error, please try again.")
- |> redirect(to: o_auth_path(conn, :registration_details, params))
+ _ ->
+ {:register, :generic_error}
end
end
- def register(conn, params) do
+ def register(conn, %{"op" => "register"} = params) do
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
%Registration{} = registration <- Repo.get(Registration, registration_id),
{:ok, user} <- Authenticator.create_from_registration(conn, params, registration) do
@@ -349,13 +352,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do
)
conn
+ |> put_status(:forbidden)
|> put_flash(:error, "Error: #{message}.")
- |> redirect(to: o_auth_path(conn, :registration_details, params))
+ |> registration_details(params)
_ ->
- conn
- |> put_flash(:error, "Unknown error, please try again.")
- |> redirect(to: o_auth_path(conn, :registration_details, params))
+ {:register, :generic_error}
end
end
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
index 002f014e6..9365c7c44 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
@@ -9,7 +9,7 @@
<%= hidden_input f, :redirect_uri, value: @redirect_uri %>
<%= hidden_input f, :state, value: @state %>
- <%= for strategy <- Pleroma.Config.get([:auth, :oauth_consumer_strategies], []) do %>
+ <%= for strategy <- Pleroma.Config.oauth_consumer_strategies() do %>
<%= submit "Sign in with #{String.capitalize(strategy)}", name: "provider", value: strategy %>
<% end %>
<% end %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index 0144675ab..87278e636 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -26,6 +26,6 @@
<%= submit "Authorize" %>
<% end %>
-<%= if Pleroma.Config.get([:auth, :oauth_consumer_enabled]) do %>
+<%= if Pleroma.Config.oauth_consumer_enabled?() do %>
<%= render @view_module, Pleroma.Web.Auth.Authenticator.oauth_consumer_template(), assigns %>
<% end %>
diff --git a/test/registration_test.exs b/test/registration_test.exs
new file mode 100644
index 000000000..6143b82c7
--- /dev/null
+++ b/test/registration_test.exs
@@ -0,0 +1,59 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.RegistrationTest do
+ use Pleroma.DataCase
+
+ import Pleroma.Factory
+
+ alias Pleroma.Registration
+ alias Pleroma.Repo
+
+ describe "generic changeset" do
+ test "requires :provider, :uid" do
+ registration = build(:registration, provider: nil, uid: nil)
+
+ cs = Registration.changeset(registration, %{})
+ refute cs.valid?
+
+ assert [
+ provider: {"can't be blank", [validation: :required]},
+ uid: {"can't be blank", [validation: :required]}
+ ] == cs.errors
+ end
+
+ test "ensures uniqueness of [:provider, :uid]" do
+ registration = insert(:registration)
+ registration2 = build(:registration, provider: registration.provider, uid: registration.uid)
+
+ cs = Registration.changeset(registration2, %{})
+ assert cs.valid?
+
+ assert {:error,
+ %Ecto.Changeset{
+ errors: [
+ uid:
+ {"has already been taken",
+ [constraint: :unique, constraint_name: "registrations_provider_uid_index"]}
+ ]
+ }} = Repo.insert(cs)
+
+ # Note: multiple :uid values per [:user_id, :provider] are intentionally allowed
+ cs2 = Registration.changeset(registration2, %{uid: "available.uid"})
+ assert cs2.valid?
+ assert {:ok, _} = Repo.insert(cs2)
+
+ cs3 = Registration.changeset(registration2, %{provider: "provider2"})
+ assert cs3.valid?
+ assert {:ok, _} = Repo.insert(cs3)
+ end
+
+ test "allows `nil` :user_id (user-unbound registration)" do
+ registration = build(:registration, user_id: nil)
+ cs = Registration.changeset(registration, %{})
+ assert cs.valid?
+ assert {:ok, _} = Repo.insert(cs)
+ end
+ end
+end
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 75333f2d5..385896dc6 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -20,16 +20,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
describe "in OAuth consumer mode, " do
setup do
- oauth_consumer_enabled_path = [:auth, :oauth_consumer_enabled]
oauth_consumer_strategies_path = [:auth, :oauth_consumer_strategies]
- oauth_consumer_enabled = Pleroma.Config.get(oauth_consumer_enabled_path)
oauth_consumer_strategies = Pleroma.Config.get(oauth_consumer_strategies_path)
-
- Pleroma.Config.put(oauth_consumer_enabled_path, true)
Pleroma.Config.put(oauth_consumer_strategies_path, ~w(twitter facebook))
on_exit(fn ->
- Pleroma.Config.put(oauth_consumer_enabled_path, oauth_consumer_enabled)
Pleroma.Config.put(oauth_consumer_strategies_path, oauth_consumer_strategies)
end)
@@ -42,7 +37,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
]
end
- test "GET /oauth/authorize also renders OAuth consumer form", %{
+ test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{
app: app,
conn: conn
} do
@@ -97,31 +92,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
} = state_components
end
- test "on authentication error, redirects to `redirect_uri`", %{app: app, conn: conn} do
- state_params = %{
- "scope" => Enum.join(app.scopes, " "),
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => ""
- }
-
- conn =
- conn
- |> assign(:ueberauth_failure, %{errors: [%{message: "unknown error"}]})
- |> get(
- "/oauth/twitter/callback",
- %{
- "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
- "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
- "provider" => "twitter",
- "state" => Poison.encode!(state_params)
- }
- )
-
- assert response = html_response(conn, 302)
- assert redirected_to(conn) == app.redirect_uris
- end
-
test "with user-bound registration, GET /oauth//callback redirects to `redirect_uri` with `code`",
%{app: app, conn: conn} do
registration = insert(:registration)
@@ -152,7 +122,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
- test "with user-unbound registration, GET /oauth//callback redirects to registration_details page",
+ test "with user-unbound registration, GET /oauth//callback renders registration_details page",
%{app: app, conn: conn} do
registration = insert(:registration, user: nil)
@@ -177,20 +147,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- expected_redirect_params =
- state_params
- |> Map.delete("scope")
- |> Map.merge(%{
- "scope" => "read write",
- "email" => Registration.email(registration),
- "nickname" => Registration.nickname(registration)
- })
+ assert response = html_response(conn, 200)
+ assert response =~ ~r/name="op" type="submit" value="register"/
+ assert response =~ ~r/name="op" type="submit" value="connect"/
+ assert response =~ Registration.email(registration)
+ assert response =~ Registration.nickname(registration)
+ end
+ end
- assert response = html_response(conn, 302)
+ test "on authentication error, GET /oauth//callback redirects to `redirect_uri`", %{
+ app: app,
+ conn: conn
+ } do
+ state_params = %{
+ "scope" => Enum.join(app.scopes, " "),
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => ""
+ }
- assert redirected_to(conn) ==
- o_auth_path(conn, :registration_details, expected_redirect_params)
- end
+ conn =
+ conn
+ |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]})
+ |> get(
+ "/oauth/twitter/callback",
+ %{
+ "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
+ "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
+ "provider" => "twitter",
+ "state" => Poison.encode!(state_params)
+ }
+ )
+
+ assert response = html_response(conn, 302)
+ assert redirected_to(conn) == app.redirect_uris
+ assert get_flash(conn, :error) == "Failed to authenticate: (error description)."
end
test "GET /oauth/registration_details renders registration details form", %{
@@ -243,7 +234,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
end
- test "with invalid params, POST /oauth/register?op=register redirects to registration_details page",
+ test "with invalid params, POST /oauth/register?op=register renders registration_details page",
%{
app: app,
conn: conn
@@ -257,19 +248,22 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"client_id" => app.client_id,
"redirect_uri" => app.redirect_uris,
"state" => "a_state",
- "nickname" => another_user.nickname,
- "email" => another_user.email
+ "nickname" => "availablenickname",
+ "email" => "available@email.com"
}
- conn =
- conn
- |> put_session(:registration_id, registration.id)
- |> post("/oauth/register", params)
+ for {bad_param, bad_param_value} <-
+ [{"nickname", another_user.nickname}, {"email", another_user.email}] do
+ bad_params = Map.put(params, bad_param, bad_param_value)
- assert response = html_response(conn, 302)
+ conn =
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> post("/oauth/register", bad_params)
- assert redirected_to(conn) ==
- o_auth_path(conn, :registration_details, params)
+ assert html_response(conn, 403) =~ ~r/name="op" type="submit" value="register"/
+ assert get_flash(conn, :error) == "Error: #{bad_param} has already been taken."
+ end
end
test "with valid params, POST /oauth/register?op=connect redirects to `redirect_uri` with `code`",
@@ -300,7 +294,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
end
- test "with invalid params, POST /oauth/register?op=connect redirects to registration_details page",
+ test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
%{
app: app,
conn: conn
@@ -323,10 +317,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|> put_session(:registration_id, registration.id)
|> post("/oauth/register", params)
- assert response = html_response(conn, 302)
-
- assert redirected_to(conn) ==
- o_auth_path(conn, :registration_details, Map.delete(params, "password"))
+ assert html_response(conn, 401) =~ ~r/name="op" type="submit" value="connect"/
+ assert get_flash(conn, :error) == "Invalid Username/Password"
end
end
--
cgit v1.2.3
From f0f30019e1c9992cb420ba54457840cddaeb6a3a Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 5 Apr 2019 15:19:44 +0300
Subject: Refactor html caching functions to have a key instead of a module,
use more correct terminology and fix summaries in mastoapi
---
lib/pleroma/html.ex | 15 +++++++--------
lib/pleroma/web/mastodon_api/views/status_view.ex | 14 +++++++++++---
lib/pleroma/web/metadata/utils.ex | 2 +-
lib/pleroma/web/twitter_api/views/activity_view.ex | 6 +++---
4 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 1e48749a8..7f1dbe28c 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -28,21 +28,20 @@ defmodule Pleroma.HTML do
def filter_tags(html), do: filter_tags(html, nil)
def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags)
- # TODO: rename object to activity because that's what it is really working with
- def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do
- key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}"
+ def get_cached_scrubbed_html_for_activity(content, scrubbers, activity, key \\ "") do
+ key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}"
Cachex.fetch!(:scrubber_cache, key, fn _key ->
- ensure_scrubbed_html(content, scrubbers, object.data["object"]["fake"] || false)
+ ensure_scrubbed_html(content, scrubbers, activity.data["object"]["fake"] || false)
end)
end
- def get_cached_stripped_html_for_object(content, object, module) do
- get_cached_scrubbed_html_for_object(
+ def get_cached_stripped_html_for_activity(content, activity, key) do
+ get_cached_scrubbed_html_for_activity(
content,
HtmlSanitizeEx.Scrubber.StripTags,
- object,
- module
+ activity,
+ key
)
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 200bb453d..4c0b53bdd 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -147,10 +147,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
content =
object
|> render_content()
- |> HTML.get_cached_scrubbed_html_for_object(
+ |> HTML.get_cached_scrubbed_html_for_activity(
User.html_filter_policy(opts[:for]),
activity,
- __MODULE__
+ "mastoapi:content"
+ )
+
+ summary =
+ (object["summary"] || "")
+ |> HTML.get_cached_scrubbed_html_for_activity(
+ User.html_filter_policy(opts[:for]),
+ activity,
+ "mastoapi:summary"
)
card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity))
@@ -182,7 +190,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user),
pinned: pinned?(activity, user),
sensitive: sensitive,
- spoiler_text: object["summary"] || "",
+ spoiler_text: summary,
visibility: get_visibility(object),
media_attachments: attachments,
mentions: mentions,
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
index 23bbde1a6..58385a3d1 100644
--- a/lib/pleroma/web/metadata/utils.ex
+++ b/lib/pleroma/web/metadata/utils.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.Metadata.Utils do
# html content comes from DB already encoded, decode first and scrub after
|> HtmlEntities.decode()
|> String.replace(~r/ /, " ")
- |> HTML.get_cached_stripped_html_for_object(object, __MODULE__)
+ |> HTML.get_cached_stripped_html_for_activity(object, "metadata")
|> Formatter.demojify()
|> Formatter.truncate()
end
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index aa1d41fa2..433322eb8 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -254,10 +254,10 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
html =
content
- |> HTML.get_cached_scrubbed_html_for_object(
+ |> HTML.get_cached_scrubbed_html_for_activity(
User.html_filter_policy(opts[:for]),
activity,
- __MODULE__
+ "twitterapi:content"
)
|> Formatter.emojify(object["emoji"])
@@ -265,7 +265,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
if content do
content
|> String.replace(~r/ /, "\n")
- |> HTML.get_cached_stripped_html_for_object(activity, __MODULE__)
+ |> HTML.get_cached_stripped_html_for_activity(activity, "twitterapi:content")
else
""
end
--
cgit v1.2.3
From f1712cd2f1ec6061f70d259f8f5e2b7e9f408d8c Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Fri, 5 Apr 2019 19:38:44 +0700
Subject: Use PleromaJobQueue in Pleroma.Web.Push
---
config/config.exs | 1 +
docs/config.md | 5 +++--
lib/pleroma/application.ex | 4 ++--
lib/pleroma/web/push/impl.ex | 6 +++---
lib/pleroma/web/push/push.ex | 48 +++++++++-----------------------------------
test/web/push/impl_test.exs | 6 ++++--
6 files changed, 23 insertions(+), 47 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index c143f79fc..d97586a61 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -356,6 +356,7 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
config :pleroma_job_queue, :queues,
federator_incoming: 50,
federator_outgoing: 50,
+ web_push: 50,
mailer: 10
config :pleroma, :fetch_initial_posts,
diff --git a/docs/config.md b/docs/config.md
index 06d6fd757..6f3119573 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -218,14 +218,14 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
- `port`
* `url` - a list containing the configuration for generating urls, accepts
- `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
- - `scheme` - e.g `http`, `https`
+ - `scheme` - e.g `http`, `https`
- `port`
- `path`
**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
-Example:
+Example:
```elixir
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "example.com", port: 2020, scheme: "https"],
@@ -317,6 +317,7 @@ Pleroma has the following queues:
* `federator_outgoing` - Outgoing federation
* `federator_incoming` - Incoming federation
* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)
+* `web_push` - Web push notifications
Example:
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 782d1d589..8f8d26814 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -109,8 +109,8 @@ defmodule Pleroma.Application do
[
worker(Pleroma.Web.Federator.RetryQueue, []),
worker(Pleroma.Stats, []),
- worker(Pleroma.Web.Push, []),
- worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary)
+ worker(Task, [&Pleroma.Web.Push.init/0], restart: :temporary, id: :web_push_init),
+ worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary, id: :federator_init)
] ++
streamer_child() ++
chat_child() ++
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 863573185..2233480c5 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -19,8 +19,8 @@ defmodule Pleroma.Web.Push.Impl do
@types ["Create", "Follow", "Announce", "Like"]
@doc "Performs sending notifications for user subscriptions"
- @spec perform_send(Notification.t()) :: list(any)
- def perform_send(
+ @spec perform(Notification.t()) :: list(any) | :error
+ def perform(
%{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} =
notif
)
@@ -50,7 +50,7 @@ defmodule Pleroma.Web.Push.Impl do
end
end
- def perform_send(_) do
+ def perform(_) do
Logger.warn("Unknown notification type")
:error
end
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index 5259e8e33..cdd50005d 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -3,18 +3,20 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push do
- use GenServer
-
alias Pleroma.Web.Push.Impl
require Logger
- ##############
- # Client API #
- ##############
+ def init() do
+ unless enabled() do
+ Logger.warn("""
+ VAPID key pair is not found. If you wish to enabled web push, please run
+
+ mix web_push.gen.keypair
- def start_link do
- GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
+ and add the resulting output to your configuration file.
+ """)
+ end
end
def vapid_config do
@@ -30,35 +32,5 @@ defmodule Pleroma.Web.Push do
end
def send(notification),
- do: GenServer.cast(__MODULE__, {:send, notification})
-
- ####################
- # Server Callbacks #
- ####################
-
- @impl true
- def init(:ok) do
- if enabled() do
- {:ok, nil}
- else
- Logger.warn("""
- VAPID key pair is not found. If you wish to enabled web push, please run
-
- mix web_push.gen.keypair
-
- and add the resulting output to your configuration file.
- """)
-
- :ignore
- end
- end
-
- @impl true
- def handle_cast({:send, notification}, state) do
- if enabled() do
- Impl.perform_send(notification)
- end
-
- {:noreply, state}
- end
+ do: PleromaJobQueue.enqueue(:web_push, Impl, [notification])
end
diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs
index 3f9f3d809..6bac2c9f6 100644
--- a/test/web/push/impl_test.exs
+++ b/test/web/push/impl_test.exs
@@ -64,17 +64,19 @@ defmodule Pleroma.Web.Push.ImplTest do
}
)
- assert Impl.perform_send(notif) == [:ok, :ok]
+ assert Impl.perform(notif) == [:ok, :ok]
end
+ @tag capture_log: true
test "returns error if notif does not match " do
- assert Impl.perform_send(%{}) == :error
+ assert Impl.perform(%{}) == :error
end
test "successful message sending" do
assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
end
+ @tag capture_log: true
test "fail message sending" do
assert Impl.push_message(
@message,
--
cgit v1.2.3
From 1c2e4f88d1a707791818014f8bcdedd986c2fa75 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Fri, 5 Apr 2019 19:46:28 +0700
Subject: fix credo
---
lib/pleroma/web/push/push.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index cdd50005d..729dad02a 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Web.Push do
require Logger
- def init() do
+ def init do
unless enabled() do
Logger.warn("""
VAPID key pair is not found. If you wish to enabled web push, please run
--
cgit v1.2.3
From 7895ee37fae82de26b3c06e69a96788d8c88d139 Mon Sep 17 00:00:00 2001
From: Roger Braun
Date: Sun, 16 Dec 2018 16:41:56 +0100
Subject: Add user following / unfollowing to the admin api.
---
lib/pleroma/web/admin_api/admin_api_controller.ex | 20 ++++++++++
lib/pleroma/web/router.ex | 4 ++
test/web/admin_api/admin_api_controller_test.exs | 46 +++++++++++++++++++++++
3 files changed, 70 insertions(+)
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index b3a09e49e..84d0aabaf 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -25,6 +25,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> json(nickname)
end
+ def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
+ with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}),
+ %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do
+ User.follow(follower, followed)
+ end
+
+ conn
+ |> json("ok")
+ end
+
+ def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
+ with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}),
+ %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do
+ User.unfollow(follower, followed)
+ end
+
+ conn
+ |> json("ok")
+ end
+
def user_create(
conn,
%{"nickname" => nickname, "email" => email, "password" => password}
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 605a327fc..1c752e44c 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -140,8 +140,12 @@ defmodule Pleroma.Web.Router do
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through([:admin_api, :oauth_write])
+ post("/user/follow", AdminAPIController, :user_follow)
+ post("/user/unfollow", AdminAPIController, :user_unfollow)
+
get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show)
+
delete("/user", AdminAPIController, :user_delete)
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
post("/user", AdminAPIController, :user_create)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index acae64361..cedc907ec 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -74,6 +74,52 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
end
+ describe "/api/pleroma/admin/user/follow" do
+ test "allows to force-follow another user" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+ follower = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> put_req_header("accept", "application/json")
+ |> post("/api/pleroma/admin/user/follow", %{
+ "follower" => follower.nickname,
+ "followed" => user.nickname
+ })
+
+ user = Repo.get(User, user.id)
+ follower = Repo.get(User, follower.id)
+
+ assert User.following?(follower, user)
+ end
+ end
+
+ describe "/api/pleroma/admin/user/unfollow" do
+ test "allows to force-unfollow another user" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+ follower = insert(:user)
+
+ User.follow(follower, user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> put_req_header("accept", "application/json")
+ |> post("/api/pleroma/admin/user/unfollow", %{
+ "follower" => follower.nickname,
+ "followed" => user.nickname
+ })
+
+ user = Repo.get(User, user.id)
+ follower = Repo.get(User, follower.id)
+
+ refute User.following?(follower, user)
+ end
+ end
+
describe "PUT /api/pleroma/admin/users/tag" do
setup do
admin = insert(:user, info: %{is_admin: true})
--
cgit v1.2.3
From da64a5aece131d6bd8c0d17dcda61c626b44c4d0 Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Fri, 5 Apr 2019 11:29:34 -0500
Subject: Document the admin API endpoints for controlling follow/unfollow
---
docs/api/admin_api.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/docs/api/admin_api.md b/docs/api/admin_api.md
index 53b68ffd4..86cacebb1 100644
--- a/docs/api/admin_api.md
+++ b/docs/api/admin_api.md
@@ -58,6 +58,26 @@ Authentication is required and the user must be an admin.
- `password`
- Response: User’s nickname
+## `/api/pleroma/admin/user/follow`
+### Make a user follow another user
+
+- Methods: `POST`
+- Params:
+ - `follower`: The nickname of the follower
+ - `followed`: The nickname of the followed
+- Response:
+ - "ok"
+
+## `/api/pleroma/admin/user/unfollow`
+### Make a user unfollow another user
+
+- Methods: `POST`
+- Params:
+ - `follower`: The nickname of the follower
+ - `followed`: The nickname of the followed
+- Response:
+ - "ok"
+
## `/api/pleroma/admin/users/:nickname/toggle_activation`
### Toggle user activation
--
cgit v1.2.3
From b5a2d384f71de9f7ff33d99c95c5db4674141d9a Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Fri, 5 Apr 2019 11:41:41 -0500
Subject: Redundant Repo.get_by usage was recently removed from the codebase
---
lib/pleroma/web/admin_api/admin_api_controller.ex | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 84d0aabaf..78bf31893 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -26,8 +26,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
- with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}),
- %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do
+ with %User{} = follower <- User.get_by_nickname(follower_nick),
+ %User{} = followed <- User.get_by_nickname(followed_nick) do
User.follow(follower, followed)
end
@@ -36,8 +36,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
- with %User{} = follower <- Repo.get_by(User, %{nickname: follower_nick}),
- %User{} = followed <- Repo.get_by(User, %{nickname: followed_nick}) do
+ with %User{} = follower <- User.get_by_nickname(follower_nick),
+ %User{} = followed <- User.get_by_nickname(followed_nick) do
User.unfollow(follower, followed)
end
--
cgit v1.2.3
From c746087f570e366976b9b89c2aa6c2a5ff83c9ca Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Fri, 5 Apr 2019 11:59:56 -0500
Subject: Also remove Repo functions in the tests
---
test/web/admin_api/admin_api_controller_test.exs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index cedc907ec..9c1cae6b7 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -89,8 +89,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"followed" => user.nickname
})
- user = Repo.get(User, user.id)
- follower = Repo.get(User, follower.id)
+ user = User.get_by_nickname(user.id)
+ follower = User.get_by_nickname(follower.id)
assert User.following?(follower, user)
end
@@ -113,8 +113,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"followed" => user.nickname
})
- user = Repo.get(User, user.id)
- follower = Repo.get(User, follower.id)
+ user = User.get_by_nickname(user.id)
+ follower = User.get_by_nickname(follower.id)
refute User.following?(follower, user)
end
--
cgit v1.2.3
From fac76bfa35f735005249111e74ea6be8670f5755 Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Fri, 5 Apr 2019 12:11:19 -0500
Subject: We actually want the user id not nickname in the test...
---
test/web/admin_api/admin_api_controller_test.exs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 9c1cae6b7..dd2fbfb15 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -89,8 +89,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"followed" => user.nickname
})
- user = User.get_by_nickname(user.id)
- follower = User.get_by_nickname(follower.id)
+ user = User.get_by_id(user.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, user)
end
@@ -113,8 +113,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"followed" => user.nickname
})
- user = User.get_by_nickname(user.id)
- follower = User.get_by_nickname(follower.id)
+ user = User.get_by_id(user.id)
+ follower = User.get_by_id(follower.id)
refute User.following?(follower, user)
end
--
cgit v1.2.3
From fb1be1d79892a72b10af2c24479e81600603a6af Mon Sep 17 00:00:00 2001
From: optikfluffel
Date: Fri, 5 Apr 2019 20:12:44 +0200
Subject: Use --cover option when running CI tests
---
.gitlab-ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c07f1a5d3..0bd657d67 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -50,7 +50,7 @@ unit-testing:
script:
- mix ecto.create
- mix ecto.migrate
- - mix test --trace --preload-modules
+ - mix test --trace --preload-modules --cover
lint:
stage: test
--
cgit v1.2.3
From e5df8cadeaa1ee3992e31e6ac00a0c391da7e4bd Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 5 Apr 2019 19:59:03 +0000
Subject: Revert "Merge branch 'test-coverage' into 'develop'"
This reverts merge request !1027
---
.gitlab-ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0bd657d67..c07f1a5d3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -50,7 +50,7 @@ unit-testing:
script:
- mix ecto.create
- mix ecto.migrate
- - mix test --trace --preload-modules --cover
+ - mix test --trace --preload-modules
lint:
stage: test
--
cgit v1.2.3
From e9c075d05c2f11b905d40ed86dd19818acf310ec Mon Sep 17 00:00:00 2001
From: Sergey Suprunenko
Date: Fri, 5 Apr 2019 22:40:30 +0200
Subject: Mock :crypt.crypt/2 because otherwise the test fails on Mac OS
---
test/plugs/legacy_authentication_plug_test.exs | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs
index 302662797..8b0b06772 100644
--- a/test/plugs/legacy_authentication_plug_test.exs
+++ b/test/plugs/legacy_authentication_plug_test.exs
@@ -47,16 +47,18 @@ defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do
|> assign(:auth_user, user)
conn =
- with_mock User,
- reset_password: fn user, %{password: password, password_confirmation: password} ->
- send(self(), :reset_password)
- {:ok, user}
- end do
- conn
- |> LegacyAuthenticationPlug.call(%{})
+ with_mocks([
+ {:crypt, [], [crypt: fn _password, password_hash -> password_hash end]},
+ {User, [],
+ [
+ reset_password: fn user, %{password: password, password_confirmation: password} ->
+ {:ok, user}
+ end
+ ]}
+ ]) do
+ LegacyAuthenticationPlug.call(conn, %{})
end
- assert_received :reset_password
assert conn.assigns.user == user
end
--
cgit v1.2.3
From 325a2680173f714a5875ed726f9171e7984f7f7a Mon Sep 17 00:00:00 2001
From: Sergey Suprunenko
Date: Fri, 5 Apr 2019 23:36:42 +0000
Subject: Redirect to the referer url after mastofe authorization
---
.../web/mastodon_api/mastodon_api_controller.ex | 19 ++++--
test/support/factory.ex | 10 ++++
.../mastodon_api/mastodon_api_controller_test.exs | 67 ++++++++++++++++++++++
3 files changed, 90 insertions(+), 6 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 89fd7629a..bcc79b08a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1091,9 +1091,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def index(%{assigns: %{user: user}} = conn, _params) do
- token =
- conn
- |> get_session(:oauth_token)
+ token = get_session(conn, :oauth_token)
if user && token do
mastodon_emoji = mastodonized_emoji()
@@ -1194,6 +1192,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> render("index.html", %{initial_state: initial_state, flavour: flavour})
else
conn
+ |> put_session(:return_to, conn.request_path)
|> redirect(to: "/web/login")
end
end
@@ -1278,12 +1277,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
scope: Enum.join(app.scopes, " ")
)
- conn
- |> redirect(to: path)
+ redirect(conn, to: path)
end
end
- defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"])
+ defp local_mastodon_root_path(conn) do
+ case get_session(conn, :return_to) do
+ nil ->
+ mastodon_api_path(conn, :index, ["getting-started"])
+
+ return_to ->
+ delete_session(conn, :return_to)
+ return_to
+ end
+ end
defp get_or_make_app do
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
diff --git a/test/support/factory.ex b/test/support/factory.ex
index e1a08315a..b37bc2c07 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -240,6 +240,16 @@ defmodule Pleroma.Factory do
}
end
+ def oauth_authorization_factory do
+ %Pleroma.Web.OAuth.Authorization{
+ token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false),
+ scopes: ["read", "write", "follow", "push"],
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10),
+ user: build(:user),
+ app: build(:oauth_app)
+ }
+ end
+
def push_subscription_factory do
%Pleroma.Web.Push.Subscription{
user: build(:user),
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 6060cc97f..438e9507d 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2340,4 +2340,71 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
refute acc_one == acc_two
assert acc_two == acc_three
end
+
+ describe "index/2 redirections" do
+ setup %{conn: conn} do
+ session_opts = [
+ store: :cookie,
+ key: "_test",
+ signing_salt: "cooldude"
+ ]
+
+ conn =
+ conn
+ |> Plug.Session.call(Plug.Session.init(session_opts))
+ |> fetch_session()
+
+ test_path = "/web/statuses/test"
+ %{conn: conn, path: test_path}
+ end
+
+ test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
+ conn = get(conn, path)
+
+ assert conn.status == 302
+ assert redirected_to(conn) == "/web/login"
+ end
+
+ test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
+ token = insert(:oauth_token)
+
+ conn =
+ conn
+ |> assign(:user, token.user)
+ |> put_session(:oauth_token, token.token)
+ |> get(path)
+
+ assert conn.status == 200
+ end
+
+ test "saves referer path to session", %{conn: conn, path: path} do
+ conn = get(conn, path)
+ return_to = Plug.Conn.get_session(conn, :return_to)
+
+ assert return_to == path
+ end
+
+ test "redirects to the saved path after log in", %{conn: conn, path: path} do
+ app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
+ auth = insert(:oauth_authorization, app: app)
+
+ conn =
+ conn
+ |> put_session(:return_to, path)
+ |> get("/web/login", %{code: auth.token})
+
+ assert conn.status == 302
+ assert redirected_to(conn) == path
+ end
+
+ test "redirects to the getting-started page when referer is not present", %{conn: conn} do
+ app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
+ auth = insert(:oauth_authorization, app: app)
+
+ conn = get(conn, "/web/login", %{code: auth.token})
+
+ assert conn.status == 302
+ assert redirected_to(conn) == "/web/getting-started"
+ end
+ end
end
--
cgit v1.2.3
From b395aebf2489f44bdb1a9c4905a51f0f26bf5fab Mon Sep 17 00:00:00 2001
From: Mark Felder
Date: Sat, 6 Apr 2019 09:30:36 -0500
Subject: Pin recon dependency to 2.4.0
---
mix.exs | 2 +-
mix.lock | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mix.exs b/mix.exs
index 6e7cff413..ec0865c4f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -101,7 +101,7 @@ defmodule Pleroma.Mixfile do
{:prometheus_phoenix, "~> 1.2"},
{:prometheus_ecto, "~> 1.4"},
{:prometheus_process_collector, "~> 1.4"},
- {:recon, github: "ferd/recon"},
+ {:recon, github: "ferd/recon", tag: "2.4.0"},
{:quack, "~> 0.1.1"}
]
end
diff --git a/mix.lock b/mix.lock
index 662fd0c6e..7c7e322de 100644
--- a/mix.lock
+++ b/mix.lock
@@ -66,7 +66,7 @@
"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"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
- "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", []},
+ "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"},
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
--
cgit v1.2.3
From 7aa53d52bd982b5ab233a65048f5fb1823127d4a Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sat, 6 Apr 2019 00:22:42 +0300
Subject: Return 403 on oauth token exchange for a deactivated user
---
lib/pleroma/web/oauth/oauth_controller.ex | 6 ++++++
test/web/oauth/oauth_controller_test.exs | 26 ++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 26d53df1a..aac8f97fc 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -152,6 +152,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)},
%App{} = app <- get_app_from_request(conn, params),
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
+ {:user_active, true} <- {:user_active, !user.info.deactivated},
scopes <- oauth_scopes(params, app.scopes),
[] <- scopes -- app.scopes,
true <- Enum.any?(scopes),
@@ -175,6 +176,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|> put_status(:forbidden)
|> json(%{error: "Your login is missing a confirmed e-mail address"})
+ {:user_active, false} ->
+ conn
+ |> put_status(:forbidden)
+ |> json(%{error: "Your account is currently disabled"})
+
_error ->
put_status(conn, 400)
|> json(%{error: "Invalid credentials"})
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index a9a0b9ed4..a68528420 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -327,6 +327,32 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
refute Map.has_key?(resp, "access_token")
end
+ test "rejects token exchange for valid credentials belonging to deactivated user" do
+ password = "testpassword"
+
+ user =
+ insert(:user,
+ password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
+ info: %{deactivated: true}
+ )
+
+ app = insert(:oauth_app)
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 403)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
+ end
+
test "rejects an invalid authorization code" do
app = insert(:oauth_app)
--
cgit v1.2.3
From 7bf622ce736af12db9b4865d8d3c2db5792d6f03 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Thu, 28 Mar 2019 12:39:10 +0300
Subject: Add scheduled activities
---
lib/pleroma/scheduled_activity.ex | 74 +++++++++++++++
lib/pleroma/web/mastodon_api/mastodon_api.ex | 7 ++
.../web/mastodon_api/mastodon_api_controller.ex | 47 ++++++++++
.../mastodon_api/views/scheduled_activity_view.ex | 23 +++++
lib/pleroma/web/router.ex | 6 ++
.../20190328053912_create_scheduled_activities.exs | 15 +++
test/support/factory.ex | 8 ++
.../mastodon_api/mastodon_api_controller_test.exs | 104 +++++++++++++++++++++
8 files changed, 284 insertions(+)
create mode 100644 lib/pleroma/scheduled_activity.ex
create mode 100644 lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
create mode 100644 priv/repo/migrations/20190328053912_create_scheduled_activities.exs
diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex
new file mode 100644
index 000000000..0c1b26a33
--- /dev/null
+++ b/lib/pleroma/scheduled_activity.ex
@@ -0,0 +1,74 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ScheduledActivity do
+ use Ecto.Schema
+
+ alias Pleroma.Repo
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.User
+
+ import Ecto.Query
+ import Ecto.Changeset
+
+ schema "scheduled_activities" do
+ belongs_to(:user, User, type: Pleroma.FlakeId)
+ field(:scheduled_at, :naive_datetime)
+ field(:params, :map)
+
+ timestamps()
+ end
+
+ def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
+ scheduled_activity
+ |> cast(attrs, [:scheduled_at, :params])
+ end
+
+ def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
+ scheduled_activity
+ |> cast(attrs, [:scheduled_at])
+ end
+
+ def new(%User{} = user, attrs) do
+ %ScheduledActivity{user_id: user.id}
+ |> changeset(attrs)
+ end
+
+ def create(%User{} = user, attrs) do
+ user
+ |> new(attrs)
+ |> Repo.insert()
+ end
+
+ def get(%User{} = user, scheduled_activity_id) do
+ ScheduledActivity
+ |> where(user_id: ^user.id)
+ |> where(id: ^scheduled_activity_id)
+ |> Repo.one()
+ end
+
+ def update(%User{} = user, scheduled_activity_id, attrs) do
+ with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
+ scheduled_activity
+ |> update_changeset(attrs)
+ |> Repo.update()
+ else
+ nil -> {:error, :not_found}
+ end
+ end
+
+ def delete(%User{} = user, scheduled_activity_id) do
+ with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
+ scheduled_activity
+ |> Repo.delete()
+ else
+ nil -> {:error, :not_found}
+ end
+ end
+
+ def for_user_query(%User{} = user) do
+ ScheduledActivity
+ |> where(user_id: ^user.id)
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index 08ea5f967..382f07e6b 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -5,6 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Pagination
+ alias Pleroma.ScheduledActivity
alias Pleroma.User
def get_followers(user, params \\ %{}) do
@@ -28,6 +29,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|> Pagination.fetch_paginated(params)
end
+ def get_scheduled_activities(user, params \\ %{}) do
+ user
+ |> ScheduledActivity.for_user_query()
+ |> Pagination.fetch_paginated(params)
+ end
+
defp cast_params(params) do
param_types = %{
exclude_types: {:array, :string}
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index bcc79b08a..0916d84dc 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
+ alias Pleroma.ScheduledActivity
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
@@ -25,6 +26,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.MastodonAPI.MastodonView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.ReportView
+ alias Pleroma.Web.MastodonAPI.ScheduledActivityView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.OAuth.App
@@ -364,6 +366,45 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do
+ with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
+ conn
+ |> add_link_headers(:scheduled_statuses, scheduled_activities)
+ |> put_view(ScheduledActivityView)
+ |> render("index.json", %{scheduled_activities: scheduled_activities})
+ end
+ end
+
+ def show_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
+ with %ScheduledActivity{} = scheduled_activity <-
+ ScheduledActivity.get(user, scheduled_activity_id) do
+ conn
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", %{scheduled_activity: scheduled_activity})
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
+ def update_scheduled_status(
+ %{assigns: %{user: user}} = conn,
+ %{"id" => scheduled_activity_id} = params
+ ) do
+ with {:ok, scheduled_activity} <-
+ ScheduledActivity.update(user, scheduled_activity_id, params) do
+ conn
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", %{scheduled_activity: scheduled_activity})
+ end
+ end
+
+ def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
+ with {:ok, %ScheduledActivity{}} <- ScheduledActivity.delete(user, scheduled_activity_id) do
+ conn
+ |> json(%{})
+ end
+ end
+
def post_status(conn, %{"status" => "", "media_ids" => media_ids} = params)
when length(media_ids) > 0 do
params =
@@ -1406,6 +1447,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
# fallback action
#
+ def errors(conn, {:error, :not_found}) do
+ conn
+ |> put_status(404)
+ |> json(%{error: "Record not found"})
+ end
+
def errors(conn, _) do
conn
|> put_status(500)
diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
new file mode 100644
index 000000000..87aa3729e
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
@@ -0,0 +1,23 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
+ use Pleroma.Web, :view
+
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.ScheduledActivityView
+
+ def render("index.json", %{scheduled_activities: scheduled_activities}) do
+ render_many(scheduled_activities, ScheduledActivityView, "show.json")
+ end
+
+ def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do
+ %{
+ id: scheduled_activity.id |> to_string,
+ scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(),
+ params: scheduled_activity.params
+ }
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 1c752e44c..3b5ac6fdd 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -244,6 +244,9 @@ defmodule Pleroma.Web.Router do
get("/notifications", MastodonAPIController, :notifications)
get("/notifications/:id", MastodonAPIController, :get_notification)
+ get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses)
+ get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status)
+
get("/lists", MastodonAPIController, :get_lists)
get("/lists/:id", MastodonAPIController, :get_list)
get("/lists/:id/accounts", MastodonAPIController, :list_accounts)
@@ -278,6 +281,9 @@ defmodule Pleroma.Web.Router do
post("/statuses/:id/mute", MastodonAPIController, :mute_conversation)
post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation)
+ put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status)
+ delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status)
+
post("/media", MastodonAPIController, :upload)
put("/media/:id", MastodonAPIController, :update_media)
diff --git a/priv/repo/migrations/20190328053912_create_scheduled_activities.exs b/priv/repo/migrations/20190328053912_create_scheduled_activities.exs
new file mode 100644
index 000000000..dc2436dce
--- /dev/null
+++ b/priv/repo/migrations/20190328053912_create_scheduled_activities.exs
@@ -0,0 +1,15 @@
+defmodule Pleroma.Repo.Migrations.CreateScheduledActivities do
+ use Ecto.Migration
+
+ def change do
+ create table(:scheduled_activities) do
+ add(:user_id, references(:users, type: :uuid, on_delete: :delete_all))
+ add(:scheduled_at, :naive_datetime, null: false)
+ add(:params, :map, null: false)
+
+ timestamps()
+ end
+
+ create(index(:scheduled_activities, [:scheduled_at]))
+ end
+end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index b37bc2c07..667f59e8c 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -23,6 +23,14 @@ defmodule Pleroma.Factory do
}
end
+ def scheduled_activity_factory do
+ %Pleroma.ScheduledActivity{
+ user: build(:user),
+ scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
+ params: build(:note) |> Map.from_struct() |> Map.get(:data)
+ }
+ end
+
def note_factory(attrs \\ %{}) do
text = sequence(:text, &"This is :moominmamma: note #{&1}")
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 438e9507d..864c0ad4d 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
+ alias Pleroma.ScheduledActivity
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
@@ -2407,4 +2408,107 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert redirected_to(conn) == "/web/getting-started"
end
end
+
+ describe "scheduled activities" do
+ test "shows scheduled activities", %{conn: conn} do
+ user = insert(:user)
+ scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
+ scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
+ scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
+ scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
+
+ conn =
+ conn
+ |> assign(:user, user)
+
+ # min_id
+ conn_res =
+ conn
+ |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
+
+ result = json_response(conn_res, 200)
+ assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
+
+ # since_id
+ conn_res =
+ conn
+ |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
+
+ result = json_response(conn_res, 200)
+ assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
+
+ # max_id
+ conn_res =
+ conn
+ |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
+
+ result = json_response(conn_res, 200)
+ assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
+ end
+
+ test "shows a scheduled activity", %{conn: conn} do
+ user = insert(:user)
+ scheduled_activity = insert(:scheduled_activity, user: user)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
+
+ assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
+ assert scheduled_activity_id == scheduled_activity.id |> to_string()
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/scheduled_statuses/404")
+
+ assert %{"error" => "Record not found"} = json_response(res_conn, 404)
+ end
+
+ test "updates a scheduled activity", %{conn: conn} do
+ user = insert(:user)
+ scheduled_activity = insert(:scheduled_activity, user: user)
+
+ new_scheduled_at =
+ NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
+ scheduled_at: new_scheduled_at
+ })
+
+ assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
+ assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
+
+ assert %{"error" => "Record not found"} = json_response(res_conn, 404)
+ end
+
+ test "deletes a scheduled activity", %{conn: conn} do
+ user = insert(:user)
+ scheduled_activity = insert(:scheduled_activity, user: user)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
+
+ assert %{} = json_response(res_conn, 200)
+ assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
+
+ assert %{"error" => "Record not found"} = json_response(res_conn, 404)
+ end
+ end
end
--
cgit v1.2.3
From b3870df51fb2f35c3e51bea435134fe3fb692ef8 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sat, 30 Mar 2019 12:58:40 +0300
Subject: Handle `scheduled_at` on status creation.
---
lib/pleroma/activity.ex | 2 +-
lib/pleroma/scheduled_activity.ex | 16 ++++++++++
.../web/mastodon_api/mastodon_api_controller.ex | 27 +++++++++++++---
.../mastodon_api/mastodon_api_controller_test.exs | 36 ++++++++++++++++++++++
4 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index bc3f8caba..ab8861b27 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Activity do
field(:data, :map)
field(:local, :boolean, default: true)
field(:actor, :string)
- field(:recipients, {:array, :string})
+ field(:recipients, {:array, :string}, default: [])
has_many(:notifications, Notification, on_delete: :delete_all)
# Attention: this is a fake relation, don't try to preload it blindly and expect it to work!
diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex
index 0c1b26a33..9fdc13990 100644
--- a/lib/pleroma/scheduled_activity.ex
+++ b/lib/pleroma/scheduled_activity.ex
@@ -12,6 +12,8 @@ defmodule Pleroma.ScheduledActivity do
import Ecto.Query
import Ecto.Changeset
+ @min_offset :timer.minutes(5)
+
schema "scheduled_activities" do
belongs_to(:user, User, type: Pleroma.FlakeId)
field(:scheduled_at, :naive_datetime)
@@ -30,6 +32,20 @@ defmodule Pleroma.ScheduledActivity do
|> cast(attrs, [:scheduled_at])
end
+ def far_enough?(scheduled_at) when is_binary(scheduled_at) do
+ with {:ok, scheduled_at} <- Ecto.Type.cast(:naive_datetime, scheduled_at) do
+ far_enough?(scheduled_at)
+ else
+ _ -> false
+ end
+ end
+
+ def far_enough?(scheduled_at) do
+ now = NaiveDateTime.utc_now()
+ diff = NaiveDateTime.diff(scheduled_at, now, :millisecond)
+ diff > @min_offset
+ end
+
def new(%User{} = user, attrs) do
%ScheduledActivity{user_id: user.id}
|> changeset(attrs)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 0916d84dc..863fc3954 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -425,12 +425,29 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
_ -> Ecto.UUID.generate()
end
- {:ok, activity} =
- Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> CommonAPI.post(user, params) end)
+ scheduled_at = params["scheduled_at"]
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do
+ {:ok, scheduled_activity} =
+ Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
+ ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at})
+ end)
+
+ conn
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", %{scheduled_activity: scheduled_activity})
+ else
+ params = Map.drop(params, ["scheduled_at"])
+
+ {:ok, activity} =
+ Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
+ CommonAPI.post(user, params)
+ end)
+
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ end
end
def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 864c0ad4d..0ec66ab73 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2410,6 +2410,42 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
describe "scheduled activities" do
+ test "creates a scheduled activity", %{conn: conn} do
+ user = insert(:user)
+ scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "scheduled",
+ "scheduled_at" => scheduled_at
+ })
+
+ assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
+ assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
+ assert [] == Repo.all(Activity)
+ end
+
+ test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
+ %{conn: conn} do
+ user = insert(:user)
+
+ scheduled_at =
+ NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "not scheduled",
+ "scheduled_at" => scheduled_at
+ })
+
+ assert %{"content" => "not scheduled"} = json_response(conn, 200)
+ assert [] == Repo.all(ScheduledActivity)
+ end
+
test "shows scheduled activities", %{conn: conn} do
user = insert(:user)
scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
--
cgit v1.2.3
From fc92a0fd8d5be0352f4791b79bda04960f36f707 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Tue, 2 Apr 2019 01:31:01 +0300
Subject: Added limits and media attachments for scheduled activities.
---
config/config.exs | 4 +
docs/config.md | 9 ++-
lib/pleroma/object.ex | 8 ++
lib/pleroma/scheduled_activity.ex | 83 +++++++++++++++----
.../web/mastodon_api/mastodon_api_controller.ex | 18 ++++-
.../mastodon_api/views/scheduled_activity_view.ex | 32 +++++++-
.../20190328053912_create_scheduled_activities.exs | 1 +
test/scheduled_activity_test.exs | 93 ++++++++++++++++++++++
test/support/factory.ex | 16 ++--
.../mastodon_api/mastodon_api_controller_test.exs | 25 ++++++
.../mastodon_api/scheduled_activity_view_test.exs | 68 ++++++++++++++++
11 files changed, 327 insertions(+), 30 deletions(-)
create mode 100644 test/scheduled_activity_test.exs
create mode 100644 test/web/mastodon_api/scheduled_activity_view_test.exs
diff --git a/config/config.exs b/config/config.exs
index 61e799f33..79cef87e6 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -367,6 +367,10 @@ config :pleroma, :fetch_initial_posts,
enabled: false,
pages: 5
+config :pleroma, Pleroma.ScheduledActivity,
+ daily_user_limit: 25,
+ total_user_limit: 100
+
config :auto_linker,
opts: [
scheme: true,
diff --git a/docs/config.md b/docs/config.md
index 06d6fd757..df21beff3 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -218,14 +218,14 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
- `port`
* `url` - a list containing the configuration for generating urls, accepts
- `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
- - `scheme` - e.g `http`, `https`
+ - `scheme` - e.g `http`, `https`
- `port`
- `path`
**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
-Example:
+Example:
```elixir
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "example.com", port: 2020, scheme: "https"],
@@ -412,3 +412,8 @@ Pleroma account will be created with the same name as the LDAP user name.
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
+
+## Pleroma.ScheduledActivity
+
+* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day
+* `total_user_limit`: the number of scheduled activities a user is allowed to create in total
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 013d62157..786d6296c 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -184,4 +184,12 @@ defmodule Pleroma.Object do
_ -> {:error, "Not found"}
end
end
+
+ def enforce_user_objects(user, object_ids) do
+ Object
+ |> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id))
+ |> where([o], o.id in ^object_ids)
+ |> select([o], o.id)
+ |> Repo.all()
+ end
end
diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex
index 9fdc13990..723eb6dc3 100644
--- a/lib/pleroma/scheduled_activity.ex
+++ b/lib/pleroma/scheduled_activity.ex
@@ -5,9 +5,12 @@
defmodule Pleroma.ScheduledActivity do
use Ecto.Schema
+ alias Pleroma.Config
+ alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.User
+ alias Pleroma.Web.CommonAPI.Utils
import Ecto.Query
import Ecto.Changeset
@@ -25,11 +28,69 @@ defmodule Pleroma.ScheduledActivity do
def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
scheduled_activity
|> cast(attrs, [:scheduled_at, :params])
+ |> validate_required([:scheduled_at, :params])
+ |> validate_scheduled_at()
+ |> with_media_attachments()
end
+ defp with_media_attachments(
+ %{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
+ )
+ when is_list(media_ids) do
+ user = User.get_cached_by_id(changeset.data.user_id)
+ media_ids = Object.enforce_user_objects(user, media_ids) |> Enum.map(&to_string(&1))
+ media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids})
+
+ params =
+ params
+ |> Map.put("media_attachments", media_attachments)
+ |> Map.put("media_ids", media_ids)
+
+ put_change(changeset, :params, params)
+ end
+
+ defp with_media_attachments(changeset), do: changeset
+
def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
scheduled_activity
|> cast(attrs, [:scheduled_at])
+ |> validate_required([:scheduled_at])
+ |> validate_scheduled_at()
+ end
+
+ def validate_scheduled_at(changeset) do
+ validate_change(changeset, :scheduled_at, fn _, scheduled_at ->
+ cond do
+ not far_enough?(scheduled_at) ->
+ [scheduled_at: "must be at least 5 minutes from now"]
+
+ exceeds_daily_user_limit?(changeset.data.user_id, scheduled_at) ->
+ [scheduled_at: "daily limit exceeded"]
+
+ exceeds_total_user_limit?(changeset.data.user_id) ->
+ [scheduled_at: "total limit exceeded"]
+
+ true ->
+ []
+ end
+ end)
+ end
+
+ def exceeds_daily_user_limit?(user_id, scheduled_at) do
+ ScheduledActivity
+ |> where(user_id: ^user_id)
+ |> where([s], type(s.scheduled_at, :date) == type(^scheduled_at, :date))
+ |> select([u], count(u.id))
+ |> Repo.one()
+ |> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit]))
+ end
+
+ def exceeds_total_user_limit?(user_id) do
+ ScheduledActivity
+ |> where(user_id: ^user_id)
+ |> select([u], count(u.id))
+ |> Repo.one()
+ |> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit]))
end
def far_enough?(scheduled_at) when is_binary(scheduled_at) do
@@ -64,23 +125,15 @@ defmodule Pleroma.ScheduledActivity do
|> Repo.one()
end
- def update(%User{} = user, scheduled_activity_id, attrs) do
- with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
- scheduled_activity
- |> update_changeset(attrs)
- |> Repo.update()
- else
- nil -> {:error, :not_found}
- end
+ def update(scheduled_activity, attrs) do
+ scheduled_activity
+ |> update_changeset(attrs)
+ |> Repo.update()
end
- def delete(%User{} = user, scheduled_activity_id) do
- with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
- scheduled_activity
- |> Repo.delete()
- else
- nil -> {:error, :not_found}
- end
+ def delete(scheduled_activity) do
+ scheduled_activity
+ |> Repo.delete()
end
def for_user_query(%User{} = user) do
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 863fc3954..6cb5df378 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -390,18 +390,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
%{assigns: %{user: user}} = conn,
%{"id" => scheduled_activity_id} = params
) do
- with {:ok, scheduled_activity} <-
- ScheduledActivity.update(user, scheduled_activity_id, params) do
+ with %ScheduledActivity{} = scheduled_activity <-
+ ScheduledActivity.get(user, scheduled_activity_id),
+ {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
conn
|> put_view(ScheduledActivityView)
|> render("show.json", %{scheduled_activity: scheduled_activity})
+ else
+ nil -> {:error, :not_found}
+ error -> error
end
end
def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
- with {:ok, %ScheduledActivity{}} <- ScheduledActivity.delete(user, scheduled_activity_id) do
+ with %ScheduledActivity{} = scheduled_activity <-
+ ScheduledActivity.get(user, scheduled_activity_id),
+ {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do
conn
- |> json(%{})
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", %{scheduled_activity: scheduled_activity})
+ else
+ nil -> {:error, :not_found}
+ error -> error
end
end
diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
index 87aa3729e..1ebff7aba 100644
--- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
alias Pleroma.ScheduledActivity
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
+ alias Pleroma.Web.MastodonAPI.StatusView
def render("index.json", %{scheduled_activities: scheduled_activities}) do
render_many(scheduled_activities, ScheduledActivityView, "show.json")
@@ -17,7 +18,36 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
%{
id: scheduled_activity.id |> to_string,
scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(),
- params: scheduled_activity.params
+ params: status_params(scheduled_activity.params)
}
+ |> with_media_attachments(scheduled_activity)
+ end
+
+ defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do
+ attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
+ Map.put(data, :media_attachments, attachments)
+ end
+
+ defp with_media_attachments(data, _), do: data
+
+ defp status_params(params) do
+ data = %{
+ text: params["status"],
+ sensitive: params["sensitive"],
+ spoiler_text: params["spoiler_text"],
+ visibility: params["visibility"],
+ scheduled_at: params["scheduled_at"],
+ poll: params["poll"],
+ in_reply_to_id: params["in_reply_to_id"]
+ }
+
+ data =
+ if media_ids = params["media_ids"] do
+ Map.put(data, :media_ids, media_ids)
+ else
+ data
+ end
+
+ data
end
end
diff --git a/priv/repo/migrations/20190328053912_create_scheduled_activities.exs b/priv/repo/migrations/20190328053912_create_scheduled_activities.exs
index dc2436dce..dd737e25a 100644
--- a/priv/repo/migrations/20190328053912_create_scheduled_activities.exs
+++ b/priv/repo/migrations/20190328053912_create_scheduled_activities.exs
@@ -11,5 +11,6 @@ defmodule Pleroma.Repo.Migrations.CreateScheduledActivities do
end
create(index(:scheduled_activities, [:scheduled_at]))
+ create(index(:scheduled_activities, [:user_id]))
end
end
diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs
new file mode 100644
index 000000000..c49c65c0a
--- /dev/null
+++ b/test/scheduled_activity_test.exs
@@ -0,0 +1,93 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ScheduledActivityTest do
+ use Pleroma.DataCase
+ alias Pleroma.Config
+ alias Pleroma.DataCase
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ import Pleroma.Factory
+
+ setup context do
+ Config.put([ScheduledActivity, :daily_user_limit], 2)
+ Config.put([ScheduledActivity, :total_user_limit], 3)
+ DataCase.ensure_local_uploader(context)
+ end
+
+ describe "creation" do
+ test "when daily user limit is exceeded" do
+ user = insert(:user)
+
+ today =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ attrs = %{params: %{}, scheduled_at: today}
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+ {:error, changeset} = ScheduledActivity.create(user, attrs)
+ assert changeset.errors == [scheduled_at: {"daily limit exceeded", []}]
+ end
+
+ test "when total user limit is exceeded" do
+ user = insert(:user)
+
+ today =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ tomorrow =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.hours(24), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today})
+ {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today})
+ {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
+ {:error, changeset} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
+ assert changeset.errors == [scheduled_at: {"total limit exceeded", []}]
+ end
+
+ test "when scheduled_at is earlier than 5 minute from now" do
+ user = insert(:user)
+
+ scheduled_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(4), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ attrs = %{params: %{}, scheduled_at: scheduled_at}
+ {:error, changeset} = ScheduledActivity.create(user, attrs)
+ assert changeset.errors == [scheduled_at: {"must be at least 5 minutes from now", []}]
+ end
+
+ test "excludes attachments belonging to another user" do
+ user = insert(:user)
+ another_user = insert(:user)
+
+ scheduled_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(10), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ {:ok, user_upload} = ActivityPub.upload(file, actor: user.ap_id)
+ {:ok, another_user_upload} = ActivityPub.upload(file, actor: another_user.ap_id)
+
+ media_ids = [user_upload.id, another_user_upload.id]
+ attrs = %{params: %{"media_ids" => media_ids}, scheduled_at: scheduled_at}
+ {:ok, scheduled_activity} = ScheduledActivity.create(user, attrs)
+ assert to_string(user_upload.id) in scheduled_activity.params["media_ids"]
+ refute to_string(another_user_upload.id) in scheduled_activity.params["media_ids"]
+ end
+ end
+end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 667f59e8c..608f8d46b 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -23,14 +23,6 @@ defmodule Pleroma.Factory do
}
end
- def scheduled_activity_factory do
- %Pleroma.ScheduledActivity{
- user: build(:user),
- scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
- params: build(:note) |> Map.from_struct() |> Map.get(:data)
- }
- end
-
def note_factory(attrs \\ %{}) do
text = sequence(:text, &"This is :moominmamma: note #{&1}")
@@ -275,4 +267,12 @@ defmodule Pleroma.Factory do
user: build(:user)
}
end
+
+ def scheduled_activity_factory do
+ %Pleroma.ScheduledActivity{
+ user: build(:user),
+ scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
+ params: build(:note) |> Map.from_struct() |> Map.get(:data)
+ }
+ 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 0ec66ab73..ae2375696 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2427,6 +2427,31 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert [] == Repo.all(Activity)
end
+ test "creates a scheduled activity with a media attachment", %{conn: conn} do
+ user = insert(:user)
+ scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
+
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "media_ids" => [to_string(upload.id)],
+ "status" => "scheduled",
+ "scheduled_at" => scheduled_at
+ })
+
+ assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
+ assert %{"type" => "image"} = media_attachment
+ end
+
test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
%{conn: conn} do
user = insert(:user)
diff --git a/test/web/mastodon_api/scheduled_activity_view_test.exs b/test/web/mastodon_api/scheduled_activity_view_test.exs
new file mode 100644
index 000000000..26747a0c0
--- /dev/null
+++ b/test/web/mastodon_api/scheduled_activity_view_test.exs
@@ -0,0 +1,68 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
+ use Pleroma.DataCase
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.MastodonAPI.ScheduledActivityView
+ alias Pleroma.Web.MastodonAPI.StatusView
+ import Pleroma.Factory
+
+ test "A scheduled activity with a media attachment" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "hi"})
+
+ scheduled_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(10), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
+
+ {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
+
+ attrs = %{
+ params: %{
+ "media_ids" => [upload.id],
+ "status" => "hi",
+ "sensitive" => true,
+ "spoiler_text" => "spoiler",
+ "visibility" => "unlisted",
+ "in_reply_to_id" => to_string(activity.id)
+ },
+ scheduled_at: scheduled_at
+ }
+
+ {:ok, scheduled_activity} = ScheduledActivity.create(user, attrs)
+ result = ScheduledActivityView.render("show.json", %{scheduled_activity: scheduled_activity})
+
+ expected = %{
+ id: to_string(scheduled_activity.id),
+ media_attachments:
+ %{"media_ids" => [upload.id]}
+ |> Utils.attachments_from_ids()
+ |> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
+ params: %{
+ in_reply_to_id: to_string(activity.id),
+ media_ids: [to_string(upload.id)],
+ poll: nil,
+ scheduled_at: nil,
+ sensitive: true,
+ spoiler_text: "spoiler",
+ text: "hi",
+ visibility: "unlisted"
+ },
+ scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at)
+ }
+
+ assert expected == result
+ end
+end
--
cgit v1.2.3
From 2056efa714460faaf25f6bc03ab643f5a2e8cd3d Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Wed, 3 Apr 2019 18:55:04 +0300
Subject: Add scheduler for sending scheduled activities to the queue
---
config/config.exs | 12 +++--
config/test.exs | 5 ++
docs/config.md | 8 +--
lib/pleroma/application.ex | 3 +-
lib/pleroma/object.ex | 8 ---
lib/pleroma/scheduled_activity.ex | 34 ++++++++++---
lib/pleroma/scheduled_activity_worker.ex | 58 ++++++++++++++++++++++
.../web/mastodon_api/mastodon_api_controller.ex | 26 +++++++---
.../mastodon_api/views/scheduled_activity_view.ex | 12 +++--
test/scheduled_activity_test.exs | 31 +-----------
test/scheduled_activity_worker_test.exs | 19 +++++++
.../mastodon_api/mastodon_api_controller_test.exs | 46 +++++++++++++++++
.../mastodon_api/scheduled_activity_view_test.exs | 2 +-
13 files changed, 196 insertions(+), 68 deletions(-)
create mode 100644 lib/pleroma/scheduled_activity_worker.ex
create mode 100644 test/scheduled_activity_worker_test.exs
diff --git a/config/config.exs b/config/config.exs
index 79cef87e6..8a977ece5 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -361,16 +361,13 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
config :pleroma_job_queue, :queues,
federator_incoming: 50,
federator_outgoing: 50,
- mailer: 10
+ mailer: 10,
+ scheduled_activities: 10
config :pleroma, :fetch_initial_posts,
enabled: false,
pages: 5
-config :pleroma, Pleroma.ScheduledActivity,
- daily_user_limit: 25,
- total_user_limit: 100
-
config :auto_linker,
opts: [
scheme: true,
@@ -396,6 +393,11 @@ config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Sendmail
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
+config :pleroma, Pleroma.ScheduledActivity,
+ daily_user_limit: 25,
+ total_user_limit: 300,
+ enabled: true
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
diff --git a/config/test.exs b/config/test.exs
index 6a7b9067e..894fa8d3d 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -50,6 +50,11 @@ config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock
config :pleroma_job_queue, disabled: true
+config :pleroma, Pleroma.ScheduledActivity,
+ daily_user_limit: 2,
+ total_user_limit: 3,
+ enabled: false
+
try do
import_config "test.secret.exs"
rescue
diff --git a/docs/config.md b/docs/config.md
index df21beff3..ba0759e87 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -317,6 +317,7 @@ Pleroma has the following queues:
* `federator_outgoing` - Outgoing federation
* `federator_incoming` - Incoming federation
* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)
+* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivities`](#pleromascheduledactivity)
Example:
@@ -413,7 +414,8 @@ Pleroma account will be created with the same name as the LDAP user name.
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
-## Pleroma.ScheduledActivity
+## Pleroma.ScheduledActivity
-* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day
-* `total_user_limit`: the number of scheduled activities a user is allowed to create in total
+* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`)
+* `total_user_limit`: the number of scheduled activities a user is allowed to create in total (Default: `300`)
+* `enabled`: whether scheduled activities are sent to the job queue to be executed
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 1fc3fb728..f0cb7d9a8 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -104,7 +104,8 @@ defmodule Pleroma.Application do
],
id: :cachex_idem
),
- worker(Pleroma.FlakeId, [])
+ worker(Pleroma.FlakeId, []),
+ worker(Pleroma.ScheduledActivityWorker, [])
] ++
hackney_pool_children() ++
[
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 786d6296c..013d62157 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -184,12 +184,4 @@ defmodule Pleroma.Object do
_ -> {:error, "Not found"}
end
end
-
- def enforce_user_objects(user, object_ids) do
- Object
- |> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id))
- |> where([o], o.id in ^object_ids)
- |> select([o], o.id)
- |> Repo.all()
- end
end
diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex
index 723eb6dc3..de0e54699 100644
--- a/lib/pleroma/scheduled_activity.ex
+++ b/lib/pleroma/scheduled_activity.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.ScheduledActivity do
use Ecto.Schema
alias Pleroma.Config
- alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.User
@@ -37,8 +36,6 @@ defmodule Pleroma.ScheduledActivity do
%{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
)
when is_list(media_ids) do
- user = User.get_cached_by_id(changeset.data.user_id)
- media_ids = Object.enforce_user_objects(user, media_ids) |> Enum.map(&to_string(&1))
media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids})
params =
@@ -79,8 +76,8 @@ defmodule Pleroma.ScheduledActivity do
def exceeds_daily_user_limit?(user_id, scheduled_at) do
ScheduledActivity
|> where(user_id: ^user_id)
- |> where([s], type(s.scheduled_at, :date) == type(^scheduled_at, :date))
- |> select([u], count(u.id))
+ |> where([sa], type(sa.scheduled_at, :date) == type(^scheduled_at, :date))
+ |> select([sa], count(sa.id))
|> Repo.one()
|> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit]))
end
@@ -88,7 +85,7 @@ defmodule Pleroma.ScheduledActivity do
def exceeds_total_user_limit?(user_id) do
ScheduledActivity
|> where(user_id: ^user_id)
- |> select([u], count(u.id))
+ |> select([sa], count(sa.id))
|> Repo.one()
|> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit]))
end
@@ -125,19 +122,40 @@ defmodule Pleroma.ScheduledActivity do
|> Repo.one()
end
- def update(scheduled_activity, attrs) do
+ def update(%ScheduledActivity{} = scheduled_activity, attrs) do
scheduled_activity
|> update_changeset(attrs)
|> Repo.update()
end
- def delete(scheduled_activity) do
+ def delete(%ScheduledActivity{} = scheduled_activity) do
scheduled_activity
|> Repo.delete()
end
+ def delete(id) when is_binary(id) or is_integer(id) do
+ ScheduledActivity
+ |> where(id: ^id)
+ |> select([sa], sa)
+ |> Repo.delete_all()
+ |> case do
+ {1, [scheduled_activity]} -> {:ok, scheduled_activity}
+ _ -> :error
+ end
+ end
+
def for_user_query(%User{} = user) do
ScheduledActivity
|> where(user_id: ^user.id)
end
+
+ def due_activities(offset \\ 0) do
+ naive_datetime =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(offset, :millisecond)
+
+ ScheduledActivity
+ |> where([sa], sa.scheduled_at < ^naive_datetime)
+ |> Repo.all()
+ end
end
diff --git a/lib/pleroma/scheduled_activity_worker.ex b/lib/pleroma/scheduled_activity_worker.ex
new file mode 100644
index 000000000..65b38622f
--- /dev/null
+++ b/lib/pleroma/scheduled_activity_worker.ex
@@ -0,0 +1,58 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ScheduledActivityWorker do
+ @moduledoc """
+ Sends scheduled activities to the job queue.
+ """
+
+ alias Pleroma.Config
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+ use GenServer
+ require Logger
+
+ @schedule_interval :timer.minutes(1)
+
+ def start_link do
+ GenServer.start_link(__MODULE__, nil)
+ end
+
+ def init(_) do
+ if Config.get([ScheduledActivity, :enabled]) do
+ schedule_next()
+ {:ok, nil}
+ else
+ :ignore
+ end
+ end
+
+ def perform(:execute, scheduled_activity_id) do
+ try do
+ {:ok, scheduled_activity} = ScheduledActivity.delete(scheduled_activity_id)
+ %User{} = user = User.get_cached_by_id(scheduled_activity.user_id)
+ {:ok, _result} = CommonAPI.post(user, scheduled_activity.params)
+ rescue
+ error ->
+ Logger.error(
+ "#{__MODULE__} Couldn't create a status from the scheduled activity: #{inspect(error)}"
+ )
+ end
+ end
+
+ def handle_info(:perform, state) do
+ ScheduledActivity.due_activities(@schedule_interval)
+ |> Enum.each(fn scheduled_activity ->
+ PleromaJobQueue.enqueue(:scheduled_activities, __MODULE__, [:execute, scheduled_activity.id])
+ end)
+
+ schedule_next()
+ {:noreply, state}
+ end
+
+ defp schedule_next do
+ Process.send_after(self(), :perform, @schedule_interval)
+ 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 6cb5df378..fc8a2458c 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
+ alias Ecto.Changeset
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Filter
@@ -438,14 +439,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
scheduled_at = params["scheduled_at"]
if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do
- {:ok, scheduled_activity} =
- Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
- ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at})
- end)
-
- conn
- |> put_view(ScheduledActivityView)
- |> render("show.json", %{scheduled_activity: scheduled_activity})
+ with {:ok, scheduled_activity} <-
+ ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do
+ conn
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", %{scheduled_activity: scheduled_activity})
+ end
else
params = Map.drop(params, ["scheduled_at"])
@@ -1474,6 +1473,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
# fallback action
#
+ def errors(conn, {:error, %Changeset{} = changeset}) do
+ error_message =
+ changeset
+ |> Changeset.traverse_errors(fn {message, _opt} -> message end)
+ |> Enum.map_join(", ", fn {_k, v} -> v end)
+
+ conn
+ |> put_status(422)
+ |> json(%{error: error_message})
+ end
+
def errors(conn, {:error, :not_found}) do
conn
|> put_status(404)
diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
index 1ebff7aba..0aae15ab9 100644
--- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
@@ -16,16 +16,20 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do
%{
- id: scheduled_activity.id |> to_string,
- scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(),
+ id: to_string(scheduled_activity.id),
+ scheduled_at: CommonAPI.Utils.to_masto_date(scheduled_activity.scheduled_at),
params: status_params(scheduled_activity.params)
}
|> with_media_attachments(scheduled_activity)
end
defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do
- attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
- Map.put(data, :media_attachments, attachments)
+ try do
+ attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
+ Map.put(data, :media_attachments, attachments)
+ rescue
+ _ -> data
+ end
end
defp with_media_attachments(data, _), do: data
diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs
index c49c65c0a..edc7cc3f9 100644
--- a/test/scheduled_activity_test.exs
+++ b/test/scheduled_activity_test.exs
@@ -4,15 +4,11 @@
defmodule Pleroma.ScheduledActivityTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.DataCase
alias Pleroma.ScheduledActivity
- alias Pleroma.Web.ActivityPub.ActivityPub
import Pleroma.Factory
setup context do
- Config.put([ScheduledActivity, :daily_user_limit], 2)
- Config.put([ScheduledActivity, :total_user_limit], 3)
DataCase.ensure_local_uploader(context)
end
@@ -42,7 +38,7 @@ defmodule Pleroma.ScheduledActivityTest do
tomorrow =
NaiveDateTime.utc_now()
- |> NaiveDateTime.add(:timer.hours(24), :millisecond)
+ |> NaiveDateTime.add(:timer.hours(36), :millisecond)
|> NaiveDateTime.to_iso8601()
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today})
@@ -64,30 +60,5 @@ defmodule Pleroma.ScheduledActivityTest do
{:error, changeset} = ScheduledActivity.create(user, attrs)
assert changeset.errors == [scheduled_at: {"must be at least 5 minutes from now", []}]
end
-
- test "excludes attachments belonging to another user" do
- user = insert(:user)
- another_user = insert(:user)
-
- scheduled_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(:timer.minutes(10), :millisecond)
- |> NaiveDateTime.to_iso8601()
-
- file = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image.jpg"),
- filename: "an_image.jpg"
- }
-
- {:ok, user_upload} = ActivityPub.upload(file, actor: user.ap_id)
- {:ok, another_user_upload} = ActivityPub.upload(file, actor: another_user.ap_id)
-
- media_ids = [user_upload.id, another_user_upload.id]
- attrs = %{params: %{"media_ids" => media_ids}, scheduled_at: scheduled_at}
- {:ok, scheduled_activity} = ScheduledActivity.create(user, attrs)
- assert to_string(user_upload.id) in scheduled_activity.params["media_ids"]
- refute to_string(another_user_upload.id) in scheduled_activity.params["media_ids"]
- end
end
end
diff --git a/test/scheduled_activity_worker_test.exs b/test/scheduled_activity_worker_test.exs
new file mode 100644
index 000000000..b9c91dda6
--- /dev/null
+++ b/test/scheduled_activity_worker_test.exs
@@ -0,0 +1,19 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ScheduledActivityWorkerTest do
+ use Pleroma.DataCase
+ alias Pleroma.ScheduledActivity
+ import Pleroma.Factory
+
+ test "creates a status from the scheduled activity" do
+ user = insert(:user)
+ scheduled_activity = insert(:scheduled_activity, user: user, params: %{status: "hi"})
+ Pleroma.ScheduledActivityWorker.perform(:execute, scheduled_activity.id)
+
+ refute Repo.get(ScheduledActivity, scheduled_activity.id)
+ activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id))
+ assert activity.data["object"]["content"] == "hi"
+ 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 ae2375696..cd01116e2 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -2471,6 +2471,52 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert [] == Repo.all(ScheduledActivity)
end
+ test "returns error when daily user limit is exceeded", %{conn: conn} do
+ user = insert(:user)
+
+ today =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ attrs = %{params: %{}, scheduled_at: today}
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
+
+ assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
+ end
+
+ test "returns error when total user limit is exceeded", %{conn: conn} do
+ user = insert(:user)
+
+ today =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ tomorrow =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(:timer.hours(36), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+
+ attrs = %{params: %{}, scheduled_at: today}
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+ {:ok, _} = ScheduledActivity.create(user, attrs)
+ {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
+
+ assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
+ end
+
test "shows scheduled activities", %{conn: conn} do
user = insert(:user)
scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
diff --git a/test/web/mastodon_api/scheduled_activity_view_test.exs b/test/web/mastodon_api/scheduled_activity_view_test.exs
index 26747a0c0..ecbb855d4 100644
--- a/test/web/mastodon_api/scheduled_activity_view_test.exs
+++ b/test/web/mastodon_api/scheduled_activity_view_test.exs
@@ -52,7 +52,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
|> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
params: %{
in_reply_to_id: to_string(activity.id),
- media_ids: [to_string(upload.id)],
+ media_ids: [upload.id],
poll: nil,
scheduled_at: nil,
sensitive: true,
--
cgit v1.2.3
From e3328bc1382315c9067c099995a29db70d9d0433 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Sun, 7 Apr 2019 11:08:37 +0300
Subject: [#923] Removed elements from auth forms, adjusted docs, minor
auth settings refactoring.
---
docs/config.md | 16 ++++++++++------
lib/pleroma/web/auth/authenticator.ex | 7 +++++--
.../web/templates/o_auth/o_auth/consumer.html.eex | 2 --
.../web/templates/o_auth/o_auth/register.html.eex | 8 +-------
4 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/docs/config.md b/docs/config.md
index 36d7f1273..686f1f36b 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -390,6 +390,11 @@ config :auto_linker,
]
```
+## Pleroma.Web.Auth.Authenticator
+
+* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
+* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
+
## :ldap
Use LDAP for user authentication. When a user logs in to the Pleroma
@@ -408,16 +413,15 @@ Pleroma account will be created with the same name as the LDAP user name.
* `base`: LDAP base, e.g. "dc=example,dc=com"
* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
-## Pleroma.Web.Auth.Authenticator
-
-* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
-* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
-
## :auth
Authentication / authorization settings.
-* `oauth_consumer_strategies`: lists enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable.
+* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`.
+* `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.
+
+# OAuth consumer mode
OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.).
Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies).
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index 4eeef5034..89d88af32 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -31,12 +31,15 @@ defmodule Pleroma.Web.Auth.Authenticator do
@callback auth_template() :: String.t() | nil
def auth_template do
- implementation().auth_template() || Pleroma.Config.get(:auth_template, "show.html")
+ # Note: `config :pleroma, :auth_template, "..."` support is deprecated
+ implementation().auth_template() ||
+ Pleroma.Config.get([:auth, :auth_template], Pleroma.Config.get(:auth_template)) ||
+ "show.html"
end
@callback oauth_consumer_template() :: String.t() | nil
def oauth_consumer_template do
implementation().oauth_consumer_template() ||
- Pleroma.Config.get(:oauth_consumer_template, "consumer.html")
+ Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
end
end
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
index 9365c7c44..85f62ca64 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
@@ -1,5 +1,3 @@
-
-
Sign in with external provider
<%= form_for @conn, o_auth_path(@conn, :prepare_request), [method: "get"], fn f -> %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
index 2e806e5fb..126390391 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
@@ -7,10 +7,7 @@
Registration Details
-If you'd like to register a new account,
-
-please provide the details below.
-
+If you'd like to register a new account, please provide the details below.
<%= form_for @conn, o_auth_path(@conn, :register), [], fn f -> %>
@@ -25,9 +22,6 @@ please provide the details below.
<%= submit "Proceed as new user", name: "op", value: "register" %>
-
-
-
Alternatively, sign in to connect to existing account.