From 1097ce6d9f06a7552652c5990cee12e7b7b3cc59 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Thu, 21 Feb 2019 18:55:19 +0300
Subject: [PATCH 001/184] Auth customization support.
OAuthController#create_authorization user retrieval / creation, errors
handling, template & layout selection.
---
lib/pleroma/web/oauth.ex | 8 +++++++
lib/pleroma/web/oauth/authenticator.ex | 22 +++++++++++++++++++
.../web/oauth/authenticator_adapter.ex | 7 ++++++
lib/pleroma/web/oauth/oauth_controller.ex | 17 +++++++-------
lib/pleroma/web/web.ex | 2 ++
5 files changed, 48 insertions(+), 8 deletions(-)
create mode 100644 lib/pleroma/web/oauth/authenticator.ex
create mode 100644 lib/pleroma/web/oauth/authenticator_adapter.ex
diff --git a/lib/pleroma/web/oauth.ex b/lib/pleroma/web/oauth.ex
index d2835a0ba..f3bac33c8 100644
--- a/lib/pleroma/web/oauth.ex
+++ b/lib/pleroma/web/oauth.ex
@@ -3,6 +3,14 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth do
+ @authenticator Application.get_env(
+ :pleroma,
+ Pleroma.Web.AuthenticatorAdapter,
+ Pleroma.Web.Authenticator
+ )
+
+ def authenticator, do: @authenticator
+
def parse_scopes(scopes, _default) when is_list(scopes) do
Enum.filter(scopes, &(&1 not in [nil, ""]))
end
diff --git a/lib/pleroma/web/oauth/authenticator.ex b/lib/pleroma/web/oauth/authenticator.ex
new file mode 100644
index 000000000..86bbc41f0
--- /dev/null
+++ b/lib/pleroma/web/oauth/authenticator.ex
@@ -0,0 +1,22 @@
+defmodule Pleroma.Web.Authenticator do
+ alias Pleroma.User
+ alias Comeonin.Pbkdf2
+
+ @behaviour Pleroma.Web.AuthenticatorAdapter
+
+ def get_user(%Plug.Conn{} = conn) do
+ %{"authorization" => %{"name" => name, "password" => password}} = conn.params
+
+ with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
+ {_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
+ {:ok, user}
+ else
+ error ->
+ {:error, error}
+ end
+ end
+
+ def handle_error(%Plug.Conn{} = _conn, error) do
+ error
+ end
+end
diff --git a/lib/pleroma/web/oauth/authenticator_adapter.ex b/lib/pleroma/web/oauth/authenticator_adapter.ex
new file mode 100644
index 000000000..282963b1c
--- /dev/null
+++ b/lib/pleroma/web/oauth/authenticator_adapter.ex
@@ -0,0 +1,7 @@
+defmodule Pleroma.Web.AuthenticatorAdapter do
+ alias Pleroma.User
+
+ @callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
+
+ @callback handle_error(Plug.Conn.t(), any()) :: any()
+end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 7c1a3adbd..abe6fd2f2 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
+ alias Pleroma.Web.OAuth
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.OAuth.App
@@ -24,27 +25,27 @@ def authorize(conn, params) do
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
- render(conn, "show.html", %{
+ template = Application.get_env(:pleroma, :auth_template, "show.html")
+
+ render(conn, template, %{
response_type: params["response_type"],
client_id: params["client_id"],
available_scopes: available_scopes,
scopes: scopes,
redirect_uri: params["redirect_uri"],
- state: params["state"]
+ state: params["state"],
+ params: params
})
end
def create_authorization(conn, %{
"authorization" =>
%{
- "name" => name,
- "password" => password,
"client_id" => client_id,
"redirect_uri" => redirect_uri
} = auth_params
}) do
- with %User{} = user <- User.get_by_nickname_or_email(name),
- true <- Pbkdf2.checkpw(password, user.password_hash),
+ with {_, {:ok, %User{} = user}} <- {:get_user, OAuth.authenticator().get_user(conn)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
scopes <- oauth_scopes(auth_params, []),
@@ -53,9 +54,9 @@ def create_authorization(conn, %{
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
- # Special case: Local MastodonFE.
redirect_uri =
if redirect_uri == "." do
+ # Special case: Local MastodonFE
mastodon_api_url(conn, :login)
else
redirect_uri
@@ -97,7 +98,7 @@ def create_authorization(conn, %{
|> authorize(auth_params)
error ->
- error
+ OAuth.authenticator().handle_error(conn, error)
end
end
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index 853aa2a87..4f618743d 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -26,6 +26,8 @@ def controller do
import Plug.Conn
import Pleroma.Web.Gettext
import Pleroma.Web.Router.Helpers
+
+ plug(:put_layout, Application.get_env(:pleroma, :app_template, "app.html"))
end
end
From afddce45b3d4d9ea61620c941838a372ca225825 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Fri, 22 Feb 2019 11:10:17 +0300
Subject: [PATCH 002/184] Minor setting name adjustment (:app_template ->
:app_layout).
---
lib/pleroma/web/web.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index 4f618743d..4bf07a6ef 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -27,7 +27,7 @@ def controller do
import Pleroma.Web.Gettext
import Pleroma.Web.Router.Helpers
- plug(:put_layout, Application.get_env(:pleroma, :app_template, "app.html"))
+ plug(:put_layout, Application.get_env(:pleroma, :app_layout, "app.html"))
end
end
From e278d470232f4e8081bbbe358137400074673e75 Mon Sep 17 00:00:00 2001
From: link0ff
Date: Fri, 22 Feb 2019 15:03:43 +0200
Subject: [PATCH 003/184] OpenLDAP support
---
config/config.exs | 9 +++
docs/config.md | 9 +++
lib/pleroma/ldap.ex | 84 +++++++++++++++++++++++
lib/pleroma/web/oauth/oauth_controller.ex | 27 +++++++-
4 files changed, 127 insertions(+), 2 deletions(-)
create mode 100644 lib/pleroma/ldap.ex
diff --git a/config/config.exs b/config/config.exs
index 6119aaea1..28d93e086 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -344,6 +344,15 @@
federator_outgoing: [max_jobs: 50],
mailer: [max_jobs: 10]
+config :pleroma, :ldap,
+ enabled: System.get_env("LDAP_ENABLED") == "true",
+ host: System.get_env("LDAP_HOST") || "localhost",
+ port: String.to_integer(System.get_env("LDAP_PORT") || "389"),
+ ssl: System.get_env("LDAP_SSL") == "true",
+ sslopts: [],
+ base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
+ uid: System.get_env("LDAP_UID") || "cn"
+
# 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/docs/config.md b/docs/config.md
index 14723b727..a497fb4ca 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -301,3 +301,12 @@ For each pool, the options are:
* `max_connections` - how much connections a pool can hold
* `timeout` - retention duration for connections
+## :ldap
+
+* `enabled`: enables LDAP authentication
+* `host`: LDAP server hostname
+* `port`: LDAP port, e.g. 389 or 636
+* `ssl`: true to use SSL
+* `sslopts`: additional SSL options
+* `base`: LDAP base, e.g. "dc=example,dc=com"
+* `uid`: attribute type to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
new file mode 100644
index 000000000..282d8e553
--- /dev/null
+++ b/lib/pleroma/ldap.ex
@@ -0,0 +1,84 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.LDAP do
+ alias Pleroma.User
+
+ require Logger
+
+ @connection_timeout 10_000
+ @search_timeout 10_000
+
+ def get_user(name, password) do
+ ldap = Pleroma.Config.get(:ldap, [])
+ host = Keyword.get(ldap, :host, "localhost")
+ port = Keyword.get(ldap, :port, 389)
+ ssl = Keyword.get(ldap, :ssl, false)
+ sslopts = Keyword.get(ldap, :sslopts, [])
+
+ options =
+ [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
+ if sslopts != [], do: [{:sslopts, sslopts}], else: []
+
+ case :eldap.open([to_charlist(host)], options) do
+ {:ok, connection} ->
+ try do
+ uid = Keyword.get(ldap, :uid, "cn")
+ base = Keyword.get(ldap, :base)
+
+ case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
+ :ok ->
+ case User.get_by_nickname_or_email(name) do
+ %User{} = user ->
+ user
+
+ _ ->
+ register_user(connection, base, uid, name, password)
+ end
+
+ error ->
+ error
+ end
+ after
+ :eldap.close(connection)
+ end
+
+ {:error, error} ->
+ Logger.error("Could not open LDAP connection: #{inspect(error)}")
+ {:error, {:ldap_connection_error, error}}
+ end
+ end
+
+ def register_user(connection, base, uid, name, password) do
+ case :eldap.search(connection, [
+ {:base, to_charlist(base)},
+ {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
+ {:scope, :eldap.wholeSubtree()},
+ {:timeout, @search_timeout}
+ ]) do
+ {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} ->
+ with {_, [mail]} <- List.keyfind(attributes, 'mail', 0) do
+ params = %{
+ email: :erlang.list_to_binary(mail),
+ name: name,
+ nickname: name,
+ password: password,
+ password_confirmation: password
+ }
+
+ changeset = User.register_changeset(%User{}, params)
+
+ case User.register(changeset) do
+ {:ok, user} -> user
+ error -> error
+ end
+ else
+ _ -> {:error, :ldap_registration_missing_attributes}
+ end
+
+ error ->
+ error
+ end
+ end
+end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 7c1a3adbd..654beb2c4 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -130,8 +130,7 @@ def token_exchange(
%{"grant_type" => "password", "username" => name, "password" => password} = params
) do
with %App{} = app <- get_app_from_request(conn, params),
- %User{} = user <- User.get_by_nickname_or_email(name),
- true <- Pbkdf2.checkpw(password, user.password_hash),
+ %User{} = user <- get_user(name, password),
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
scopes <- oauth_scopes(params, app.scopes),
[] <- scopes -- app.scopes,
@@ -215,4 +214,28 @@ defp get_app_from_request(conn, params) do
nil
end
end
+
+ defp get_user(name, password) do
+ if Pleroma.Config.get([:ldap, :enabled]) do
+ case Pleroma.LDAP.get_user(name, password) do
+ %User{} = user ->
+ user
+
+ {:error, {:ldap_connection_error, _}} ->
+ # When LDAP is unavailable, try default login
+ with %User{} = user <- User.get_by_nickname_or_email(name),
+ true <- Pbkdf2.checkpw(password, user.password_hash) do
+ user
+ end
+
+ error ->
+ error
+ end
+ else
+ with %User{} = user <- User.get_by_nickname_or_email(name),
+ true <- Pbkdf2.checkpw(password, user.password_hash) do
+ user
+ end
+ end
+ end
end
From efa506b874a0caf85800ec91f1aef4b2878840d3 Mon Sep 17 00:00:00 2001
From: 11backslashes
Date: Sun, 24 Feb 2019 13:23:47 -0500
Subject: [PATCH 004/184] delegate user retrieval to the User module
---
lib/pleroma/web/twitter_api/twitter_api.ex | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index efdd0bf43..ab6470d78 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -229,18 +229,10 @@ def password_reset(nickname_or_email) do
end
end
- def get_by_id_or_nickname(id_or_nickname) do
- if !is_integer(id_or_nickname) && :error == Integer.parse(id_or_nickname) do
- Repo.get_by(User, nickname: id_or_nickname)
- else
- Repo.get(User, id_or_nickname)
- end
- end
-
def get_user(user \\ nil, params) do
case params do
%{"user_id" => user_id} ->
- case target = get_by_id_or_nickname(user_id) do
+ case target = User.get_cached_by_nickname_or_id(user_id) do
nil ->
{:error, "No user with such user_id"}
From fc9d895ebc71cb89192e23f7dca0a7fabaa2cdab Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Sun, 24 Feb 2019 18:53:49 +0000
Subject: [PATCH 005/184] twitter card: remove IO.inspect() spam
---
lib/pleroma/web/metadata/twitter_card.ex | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lib/pleroma/web/metadata/twitter_card.ex b/lib/pleroma/web/metadata/twitter_card.ex
index d672b397f..a0be383e5 100644
--- a/lib/pleroma/web/metadata/twitter_card.ex
+++ b/lib/pleroma/web/metadata/twitter_card.ex
@@ -66,9 +66,7 @@ def build_tags(%{user: user}) do
end
end
- defp build_attachments(id, z = %{data: %{"attachment" => attachments}}) do
- IO.puts(inspect(z))
-
+ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do
Enum.reduce(attachments, [], fn attachment, acc ->
rendered_tags =
Enum.reduce(attachment["url"], [], fn url, acc ->
From d3a6c065a496c3a7c4f0604af646b6fb611f585b Mon Sep 17 00:00:00 2001
From: PEA
Date: Mon, 25 Feb 2019 23:37:46 -0500
Subject: [PATCH 006/184] Add ipv6 handling to pleroma.nginx
Replaces `listen 80` with `listen [::]:80`, same with 443
---
installation/pleroma.nginx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx
index a3d55e4bf..66a0e987c 100644
--- a/installation/pleroma.nginx
+++ b/installation/pleroma.nginx
@@ -11,7 +11,7 @@ proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cac
server {
server_name example.tld;
- listen 80;
+ listen [::]:80;
return 301 https://$server_name$request_uri;
# Uncomment this if you need to use the 'webroot' method with certbot. Make sure
@@ -29,7 +29,7 @@ server {
ssl_session_cache shared:ssl_session_cache:10m;
server {
- listen 443 ssl http2;
+ listen [::]:443 ssl http2;
ssl_session_timeout 5m;
ssl_trusted_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
From e82b70eb530293c3dfe8597c4100320fba96e479 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Tue, 26 Feb 2019 15:27:01 +0300
Subject: [PATCH 007/184] Database authenticator behaviour / Pleroma
implementation refactoring.
---
lib/pleroma/web/auth/database_authenticator.ex | 14 ++++++++++++++
.../pleroma_database_authenticator.ex} | 4 ++--
lib/pleroma/web/oauth.ex | 8 --------
lib/pleroma/web/oauth/authenticator_adapter.ex | 7 -------
lib/pleroma/web/oauth/oauth_controller.ex | 6 +++---
5 files changed, 19 insertions(+), 20 deletions(-)
create mode 100644 lib/pleroma/web/auth/database_authenticator.ex
rename lib/pleroma/web/{oauth/authenticator.ex => auth/pleroma_database_authenticator.ex} (81%)
delete mode 100644 lib/pleroma/web/oauth/authenticator_adapter.ex
diff --git a/lib/pleroma/web/auth/database_authenticator.ex b/lib/pleroma/web/auth/database_authenticator.ex
new file mode 100644
index 000000000..69024a4ba
--- /dev/null
+++ b/lib/pleroma/web/auth/database_authenticator.ex
@@ -0,0 +1,14 @@
+defmodule Pleroma.Web.Auth.DatabaseAuthenticator do
+ alias Pleroma.User
+
+ @implementation Pleroma.Config.get(
+ Pleroma.Web.Auth.DatabaseAuthenticator,
+ Pleroma.Web.Auth.PleromaDatabaseAuthenticator
+ )
+
+ @callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
+ defdelegate get_user(plug), to: @implementation
+
+ @callback handle_error(Plug.Conn.t(), any()) :: any()
+ defdelegate handle_error(plug, error), to: @implementation
+end
diff --git a/lib/pleroma/web/oauth/authenticator.ex b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
similarity index 81%
rename from lib/pleroma/web/oauth/authenticator.ex
rename to lib/pleroma/web/auth/pleroma_database_authenticator.ex
index 86bbc41f0..79a8dcfce 100644
--- a/lib/pleroma/web/oauth/authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
@@ -1,8 +1,8 @@
-defmodule Pleroma.Web.Authenticator do
+defmodule Pleroma.Web.Auth.PleromaDatabaseAuthenticator do
alias Pleroma.User
alias Comeonin.Pbkdf2
- @behaviour Pleroma.Web.AuthenticatorAdapter
+ @behaviour Pleroma.Web.Auth.DatabaseAuthenticator
def get_user(%Plug.Conn{} = conn) do
%{"authorization" => %{"name" => name, "password" => password}} = conn.params
diff --git a/lib/pleroma/web/oauth.ex b/lib/pleroma/web/oauth.ex
index f3bac33c8..d2835a0ba 100644
--- a/lib/pleroma/web/oauth.ex
+++ b/lib/pleroma/web/oauth.ex
@@ -3,14 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth do
- @authenticator Application.get_env(
- :pleroma,
- Pleroma.Web.AuthenticatorAdapter,
- Pleroma.Web.Authenticator
- )
-
- def authenticator, do: @authenticator
-
def parse_scopes(scopes, _default) when is_list(scopes) do
Enum.filter(scopes, &(&1 not in [nil, ""]))
end
diff --git a/lib/pleroma/web/oauth/authenticator_adapter.ex b/lib/pleroma/web/oauth/authenticator_adapter.ex
deleted file mode 100644
index 282963b1c..000000000
--- a/lib/pleroma/web/oauth/authenticator_adapter.ex
+++ /dev/null
@@ -1,7 +0,0 @@
-defmodule Pleroma.Web.AuthenticatorAdapter do
- alias Pleroma.User
-
- @callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
-
- @callback handle_error(Plug.Conn.t(), any()) :: any()
-end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index abe6fd2f2..02c0babd2 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
- alias Pleroma.Web.OAuth
+ alias Pleroma.Web.Auth.DatabaseAuthenticator
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.OAuth.App
@@ -45,7 +45,7 @@ def create_authorization(conn, %{
"redirect_uri" => redirect_uri
} = auth_params
}) do
- with {_, {:ok, %User{} = user}} <- {:get_user, OAuth.authenticator().get_user(conn)},
+ with {_, {:ok, %User{} = user}} <- {:get_user, DatabaseAuthenticator.get_user(conn)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
scopes <- oauth_scopes(auth_params, []),
@@ -98,7 +98,7 @@ def create_authorization(conn, %{
|> authorize(auth_params)
error ->
- OAuth.authenticator().handle_error(conn, error)
+ DatabaseAuthenticator.handle_error(conn, error)
end
end
From e98d34e5fb569b52166f74a1fc255310938d657c Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Tue, 26 Feb 2019 16:26:54 +0300
Subject: [PATCH 008/184] Added missing copyright headers.
---
lib/pleroma/web/auth/database_authenticator.ex | 4 ++++
lib/pleroma/web/auth/pleroma_database_authenticator.ex | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/lib/pleroma/web/auth/database_authenticator.ex b/lib/pleroma/web/auth/database_authenticator.ex
index 69024a4ba..02a16b634 100644
--- a/lib/pleroma/web/auth/database_authenticator.ex
+++ b/lib/pleroma/web/auth/database_authenticator.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Auth.DatabaseAuthenticator do
alias Pleroma.User
diff --git a/lib/pleroma/web/auth/pleroma_database_authenticator.ex b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
index 79a8dcfce..39aa1a586 100644
--- a/lib/pleroma/web/auth/pleroma_database_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.Auth.PleromaDatabaseAuthenticator do
alias Pleroma.User
alias Comeonin.Pbkdf2
From e1bdaaa3fe20ad10458afa5edfb161fedcea74c0 Mon Sep 17 00:00:00 2001
From: Kenneth Zhao
Date: Tue, 26 Feb 2019 08:41:37 -0800
Subject: [PATCH 009/184] need to put back ipv4 listen instruct
---
installation/pleroma.nginx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx
index 66a0e987c..8709f2cb7 100644
--- a/installation/pleroma.nginx
+++ b/installation/pleroma.nginx
@@ -11,6 +11,8 @@ proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cac
server {
server_name example.tld;
+
+ listen 80;
listen [::]:80;
return 301 https://$server_name$request_uri;
@@ -29,6 +31,9 @@ server {
ssl_session_cache shared:ssl_session_cache:10m;
server {
+ server_name example.tld;
+
+ listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_session_timeout 5m;
@@ -48,8 +53,6 @@ server {
ssl_stapling on;
ssl_stapling_verify on;
- server_name example.tld;
-
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
From 90d0d055fccc630066e66627281432e382aefdb1 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Wed, 27 Feb 2019 00:13:38 +0300
Subject: [PATCH 010/184] Add more admin actions
---
lib/pleroma/user.ex | 6 ++++++
.../web/admin_api/admin_api_controller.ex | 17 +++++++++++++++++
lib/pleroma/web/router.ex | 2 ++
lib/pleroma/web/twitter_api/views/user_view.ex | 14 ++++++++++++++
4 files changed, 39 insertions(+)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index c98b942ff..12e0e818e 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -772,6 +772,12 @@ def search(query, resolve \\ false, for_user \\ nil) do
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
end
+ def all_except_one(user) do
+ query = from(u in User, where: u.id != ^user.id)
+
+ Repo.all(query)
+ end
+
defp do_search(subquery, for_user, options \\ []) do
q =
from(
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 9ec50bb90..ef72509fe 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
+ alias Pleroma.Web.TwitterAPI.UserView
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
@@ -41,6 +42,15 @@ def user_create(
|> json(user.nickname)
end
+ def user_toggle_activation(conn, %{"nickname" => nickname}) do
+ user = User.get_by_nickname(nickname)
+
+ {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
+
+ conn
+ |> json(UserView.render("show_for_admin.json", %{user: updated_user}))
+ end
+
def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
with {:ok, _} <- User.tag(nicknames, tags),
do: json_response(conn, :no_content, "")
@@ -51,6 +61,13 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
do: json_response(conn, :no_content, "")
end
+ def list_users(%{assigns: %{user: admin}} = conn, _data) do
+ users = User.all_except_one(admin)
+
+ conn
+ |> json(UserView.render("index_for_admin.json", %{users: users}))
+ end
+
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
when permission_group in ["moderator", "admin"] do
user = User.get_by_nickname(nickname)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 5aebcb353..3b1fd46a5 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -139,7 +139,9 @@ defmodule Pleroma.Web.Router do
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through([:admin_api, :oauth_write])
+ get("/users", AdminAPIController, :list_users)
delete("/user", AdminAPIController, :user_delete)
+ patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
post("/user", AdminAPIController, :user_create)
put("/users/tag", AdminAPIController, :tag_users)
delete("/users/tag", AdminAPIController, :untag_users)
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index df7384476..c5034cf36 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MediaProxy
+ alias Pleroma.Web.TwitterAPI.UserView
def render("show.json", %{user: user = %User{}} = assigns) do
render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns)
@@ -26,6 +27,19 @@ def render("user.json", %{user: user = %User{}} = assigns) do
else: %{}
end
+ def render("index_for_admin.json", %{users: users} = opts) do
+ users
+ |> render_many(UserView, "show_for_admin.json", opts)
+ end
+
+ def render("show_for_admin.json", %{user: user}) do
+ %{
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "deactivated" => user.info.deactivated
+ }
+ end
+
def render("short.json", %{
user: %User{
nickname: nickname,
From c3ac9424d2affe87df82c14dc243f507fa639343 Mon Sep 17 00:00:00 2001
From: Egor
Date: Tue, 26 Feb 2019 23:32:26 +0000
Subject: [PATCH 011/184] AutoLinker
---
config/config.exs | 10 +
docs/config.md | 27 ++-
lib/pleroma/formatter.ex | 194 +++++-------------
lib/pleroma/user.ex | 6 +-
lib/pleroma/web/common_api/common_api.ex | 28 +--
lib/pleroma/web/common_api/utils.ex | 86 ++++----
mix.exs | 5 +-
mix.lock | 1 +
test/formatter_test.exs | 112 ++++------
test/web/common_api/common_api_utils_test.exs | 32 ++-
10 files changed, 211 insertions(+), 290 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 6119aaea1..7e4ac1100 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -344,6 +344,16 @@
federator_outgoing: [max_jobs: 50],
mailer: [max_jobs: 10]
+config :auto_linker,
+ opts: [
+ scheme: true,
+ extra: true,
+ class: false,
+ strip_prefix: false,
+ new_window: false,
+ rel: false
+ ]
+
# 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/docs/config.md b/docs/config.md
index 14723b727..d1bf2a6f4 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -107,7 +107,7 @@ config :pleroma, Pleroma.Mailer,
An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed:
```
-config :logger,
+config :logger,
backends: [{ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger,
@@ -301,3 +301,28 @@ For each pool, the options are:
* `max_connections` - how much connections a pool can hold
* `timeout` - retention duration for connections
+## :auto_linker
+
+Configuration for the `auto_linker` library:
+
+* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear
+* `rel: "noopener noreferrer"` - override the rel attribute. false to clear
+* `new_window: true` - set to false to remove `target='_blank'` attribute
+* `scheme: false` - Set to true to link urls with schema `http://google.com`
+* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..`
+* `strip_prefix: true` - Strip the scheme prefix
+* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.)
+
+Example:
+
+```exs
+config :auto_linker,
+ opts: [
+ scheme: true,
+ extra: true,
+ class: false,
+ strip_prefix: false,
+ new_window: false,
+ rel: false
+ ]
+```
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index f31aafa0d..51d08c5ee 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -8,33 +8,51 @@ defmodule Pleroma.Formatter do
alias Pleroma.User
alias Pleroma.Web.MediaProxy
- @tag_regex ~r/((?<=[^&])|\A)(\#)(\w+)/u
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
+ @link_regex ~r{((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+}ui
- # Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
- @mentions_regex ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]*@?[a-zA-Z0-9_-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
+ @auto_linker_config hashtag: true,
+ hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
+ mention: true,
+ mention_handler: &Pleroma.Formatter.mention_handler/4
- def parse_tags(text, data \\ %{}) do
- Regex.scan(@tag_regex, text)
- |> Enum.map(fn ["#" <> tag = full_tag | _] -> {full_tag, String.downcase(tag)} end)
- |> (fn map ->
- if data["sensitive"] in [true, "True", "true", "1"],
- do: [{"#nsfw", "nsfw"}] ++ map,
- else: map
- end).()
+ def mention_handler("@" <> nickname, buffer, opts, acc) do
+ case User.get_cached_by_nickname(nickname) do
+ %User{id: id} = user ->
+ ap_id = get_ap_id(user)
+ nickname_text = get_nickname_text(nickname, opts) |> maybe_escape(opts)
+
+ link =
+ "@#{
+ nickname_text
+ } "
+
+ {link, %{acc | mentions: MapSet.put(acc.mentions, {"@" <> nickname, user})}}
+
+ _ ->
+ {buffer, acc}
+ end
end
- @doc "Parses mentions text and returns list {nickname, user}."
- @spec parse_mentions(binary()) :: list({binary(), User.t()})
- def parse_mentions(text) do
- Regex.scan(@mentions_regex, text)
- |> List.flatten()
- |> Enum.uniq()
- |> Enum.map(fn nickname ->
- with nickname <- String.trim_leading(nickname, "@"),
- do: {"@" <> nickname, User.get_cached_by_nickname(nickname)}
- end)
- |> Enum.filter(fn {_match, user} -> user end)
+ def hashtag_handler("#" <> tag = tag_text, _buffer, _opts, acc) do
+ tag = String.downcase(tag)
+ url = "#{Pleroma.Web.base_url()}/tag/#{tag}"
+ link = "#{tag_text} "
+
+ {link, %{acc | tags: MapSet.put(acc.tags, {tag_text, tag})}}
+ end
+
+ @doc """
+ Parses a text and replace plain text links with HTML. Returns a tuple with a result text, mentions, and hashtags.
+ """
+ @spec linkify(String.t(), keyword()) ::
+ {String.t(), [{String.t(), User.t()}], [{String.t(), String.t()}]}
+ def linkify(text, options \\ []) do
+ options = options ++ @auto_linker_config
+ acc = %{mentions: MapSet.new(), tags: MapSet.new()}
+ {text, %{mentions: mentions, tags: tags}} = AutoLinker.link_map(text, acc, options)
+
+ {text, MapSet.to_list(mentions), MapSet.to_list(tags)}
end
def emojify(text) do
@@ -48,9 +66,7 @@ def emojify(text, emoji, strip \\ false) do
emoji = HTML.strip_tags(emoji)
file = HTML.strip_tags(file)
- String.replace(
- text,
- ":#{emoji}:",
+ html =
if not strip do
" Enum.join("")
end
- @doc """
- Escapes a special characters in mention names.
- """
- @spec mentions_escape(String.t(), list({String.t(), any()})) :: String.t()
- def mentions_escape(text, mentions) do
- mentions
- |> Enum.reduce(text, fn {name, _}, acc ->
- escape_name = String.replace(name, @markdown_characters_regex, "\\\\\\1")
- String.replace(acc, name, escape_name)
- end)
- end
-
- @doc "changes scheme:... urls to html links"
- def add_links({subs, text}) do
- links =
- text
- |> String.split([" ", "\t", " "])
- |> Enum.filter(fn word -> String.starts_with?(word, @valid_schemes) end)
- |> Enum.filter(fn word -> Regex.match?(@link_regex, word) end)
- |> Enum.map(fn url -> {Ecto.UUID.generate(), url} end)
- |> Enum.sort_by(fn {_, url} -> -String.length(url) end)
-
- uuid_text =
- links
- |> Enum.reduce(text, fn {uuid, url}, acc -> String.replace(acc, url, uuid) end)
-
- subs =
- subs ++
- Enum.map(links, fn {uuid, url} ->
- {uuid, "#{url} "}
- end)
-
- {subs, uuid_text}
- end
-
- @doc "Adds the links to mentioned users"
- def add_user_links({subs, text}, mentions, options \\ []) do
- mentions =
- mentions
- |> Enum.sort_by(fn {name, _} -> -String.length(name) end)
- |> Enum.map(fn {name, user} -> {name, user, Ecto.UUID.generate()} end)
-
- uuid_text =
- mentions
- |> Enum.reduce(text, fn {match, _user, uuid}, text ->
- String.replace(text, match, uuid)
- end)
-
- subs =
- subs ++
- Enum.map(mentions, fn {match, %User{id: id, ap_id: ap_id, info: info}, uuid} ->
- ap_id =
- if is_binary(info.source_data["url"]) do
- info.source_data["url"]
- else
- ap_id
- end
-
- nickname =
- if options[:format] == :full do
- User.full_nickname(match)
- else
- User.local_nickname(match)
- end
-
- {uuid,
- "" <>
- "@#{nickname} "}
- end)
-
- {subs, uuid_text}
- end
-
- @doc "Adds the hashtag links"
- def add_hashtag_links({subs, text}, tags) do
- tags =
- tags
- |> Enum.sort_by(fn {name, _} -> -String.length(name) end)
- |> Enum.map(fn {name, short} -> {name, short, Ecto.UUID.generate()} end)
-
- uuid_text =
- tags
- |> Enum.reduce(text, fn {match, _short, uuid}, text ->
- String.replace(text, ~r/((?<=[^&])|(\A))#{match}/, uuid)
- end)
-
- subs =
- subs ++
- Enum.map(tags, fn {tag_text, tag, uuid} ->
- url =
- "#{
- tag_text
- } "
-
- {uuid, url}
- end)
-
- {subs, uuid_text}
- end
-
- def finalize({subs, text}) do
- Enum.reduce(subs, text, fn {uuid, replacement}, result_text ->
- String.replace(result_text, uuid, replacement)
- end)
- end
-
def truncate(text, max_length \\ 200, omission \\ "...") do
# Remove trailing whitespace
text = Regex.replace(~r/([^ \t\r\n])([ \t]+$)/u, text, "\\g{1}")
@@ -211,4 +115,16 @@ def truncate(text, max_length \\ 200, omission \\ "...") do
String.slice(text, 0, length_with_omission) <> omission
end
end
+
+ defp get_ap_id(%User{info: %{source_data: %{"url" => url}}}) when is_binary(url), do: url
+ defp get_ap_id(%User{ap_id: ap_id}), do: ap_id
+
+ defp get_nickname_text(nickname, %{mentions_format: :full}), do: User.full_nickname(nickname)
+ defp get_nickname_text(nickname, _), do: User.local_nickname(nickname)
+
+ defp maybe_escape(str, %{mentions_escape: true}) do
+ String.replace(str, @markdown_characters_regex, "\\\\\\1")
+ end
+
+ defp maybe_escape(str, _), do: str
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 12e0e818e..01d532ab3 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1193,9 +1193,6 @@ def parse_bio(nil, _user), do: ""
def parse_bio(bio, _user) when bio == "", do: bio
def parse_bio(bio, user) do
- mentions = Formatter.parse_mentions(bio)
- tags = Formatter.parse_tags(bio)
-
emoji =
(user.info.source_data["tag"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
@@ -1204,7 +1201,8 @@ def parse_bio(bio, user) do
end)
bio
- |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full])
+ |> CommonUtils.format_input("text/plain", mentions_format: :full)
+ |> elem(0)
|> Formatter.emojify(emoji)
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index e788337cc..7114d6de6 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -82,40 +82,20 @@ def get_visibility(%{"in_reply_to_status_id" => status_id}) when not is_nil(stat
def get_visibility(_), do: "public"
- defp get_content_type(content_type) do
- if Enum.member?(Pleroma.Config.get([:instance, :allowed_post_formats]), content_type) do
- content_type
- else
- "text/plain"
- end
- end
-
def post(user, %{"status" => status} = data) do
visibility = get_visibility(data)
limit = Pleroma.Config.get([:instance, :limit])
with status <- String.trim(status),
attachments <- attachments_from_ids(data),
- mentions <- Formatter.parse_mentions(status),
inReplyTo <- get_replied_to_activity(data["in_reply_to_status_id"]),
- {to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
- tags <- Formatter.parse_tags(status, data),
- content_html <-
+ {content_html, mentions, tags} <-
make_content_html(
status,
- mentions,
attachments,
- tags,
- get_content_type(data["content_type"]),
- Enum.member?(
- [true, "true"],
- Map.get(
- data,
- "no_attachment_links",
- Pleroma.Config.get([:instance, :no_attachment_links], false)
- )
- )
+ data
),
+ {to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
context <- make_context(inReplyTo),
cw <- data["spoiler_text"],
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
@@ -247,7 +227,7 @@ def thread_muted?(user, activity) do
def report(user, data) do
with {:account_id, %{"account_id" => account_id}} <- {:account_id, data},
{:account, %User{} = account} <- {:account, User.get_by_id(account_id)},
- {:ok, content_html} <- make_report_content_html(data["comment"]),
+ {:ok, {content_html, _, _}} <- make_report_content_html(data["comment"]),
{:ok, statuses} <- get_report_statuses(account, data),
{:ok, activity} <-
ActivityPub.flag(%{
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 1d3a314ce..20123854d 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web
+ alias Pleroma.Config
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.ActivityPub.Utils
@@ -100,24 +100,45 @@ def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
def make_content_html(
status,
- mentions,
attachments,
- tags,
- content_type,
- no_attachment_links \\ false
+ data
) do
+ no_attachment_links =
+ data
+ |> Map.get("no_attachment_links", Config.get([:instance, :no_attachment_links]))
+ |> Kernel.in([true, "true"])
+
+ content_type = get_content_type(data["content_type"])
+
status
- |> format_input(mentions, tags, content_type)
+ |> format_input(content_type)
|> maybe_add_attachments(attachments, no_attachment_links)
+ |> maybe_add_nsfw_tag(data)
end
+ defp get_content_type(content_type) do
+ if Enum.member?(Config.get([:instance, :allowed_post_formats]), content_type) do
+ content_type
+ else
+ "text/plain"
+ end
+ end
+
+ defp maybe_add_nsfw_tag({text, mentions, tags}, %{"sensitive" => sensitive})
+ when sensitive in [true, "True", "true", "1"] do
+ {text, mentions, [{"#nsfw", "nsfw"} | tags]}
+ end
+
+ defp maybe_add_nsfw_tag(data, _), do: data
+
def make_context(%Activity{data: %{"context" => context}}), do: context
def make_context(_), do: Utils.generate_context_id()
- def maybe_add_attachments(text, _attachments, true = _no_links), do: text
+ def maybe_add_attachments(parsed, _attachments, true = _no_links), do: parsed
- def maybe_add_attachments(text, attachments, _no_links) do
- add_attachments(text, attachments)
+ def maybe_add_attachments({text, mentions, tags}, attachments, _no_links) do
+ text = add_attachments(text, attachments)
+ {text, mentions, tags}
end
def add_attachments(text, attachments) do
@@ -135,56 +156,39 @@ def add_attachments(text, attachments) do
Enum.join([text | attachment_text], " ")
end
- def format_input(text, mentions, tags, format, options \\ [])
+ def format_input(text, format, options \\ [])
@doc """
Formatting text to plain text.
"""
- def format_input(text, mentions, tags, "text/plain", options) do
+ def format_input(text, "text/plain", options) do
text
|> Formatter.html_escape("text/plain")
- |> String.replace(~r/\r?\n/, " ")
- |> (&{[], &1}).()
- |> Formatter.add_links()
- |> Formatter.add_user_links(mentions, options[:user_links] || [])
- |> Formatter.add_hashtag_links(tags)
- |> Formatter.finalize()
+ |> Formatter.linkify(options)
+ |> (fn {text, mentions, tags} ->
+ {String.replace(text, ~r/\r?\n/, " "), mentions, tags}
+ end).()
end
@doc """
Formatting text to html.
"""
- def format_input(text, mentions, _tags, "text/html", options) do
+ def format_input(text, "text/html", options) do
text
|> Formatter.html_escape("text/html")
- |> (&{[], &1}).()
- |> Formatter.add_user_links(mentions, options[:user_links] || [])
- |> Formatter.finalize()
+ |> Formatter.linkify(options)
end
@doc """
Formatting text to markdown.
"""
- def format_input(text, mentions, tags, "text/markdown", options) do
+ def format_input(text, "text/markdown", options) do
+ options = Keyword.put(options, :mentions_escape, true)
+
text
- |> Formatter.mentions_escape(mentions)
- |> Earmark.as_html!()
|> Formatter.html_escape("text/html")
- |> (&{[], &1}).()
- |> Formatter.add_user_links(mentions, options[:user_links] || [])
- |> Formatter.add_hashtag_links(tags)
- |> Formatter.finalize()
- end
-
- def add_tag_links(text, tags) do
- tags =
- tags
- |> Enum.sort_by(fn {tag, _} -> -String.length(tag) end)
-
- Enum.reduce(tags, text, fn {full, tag}, text ->
- url = "##{tag} "
- String.replace(text, full, url)
- end)
+ |> Formatter.linkify(options)
+ |> (fn {text, mentions, tags} -> {Earmark.as_html!(text), mentions, tags} end).()
end
def make_note_data(
@@ -323,13 +327,13 @@ def maybe_extract_mentions(%{"tag" => tag}) do
def maybe_extract_mentions(_), do: []
- def make_report_content_html(nil), do: {:ok, nil}
+ def make_report_content_html(nil), do: {:ok, {nil, [], []}}
def make_report_content_html(comment) do
max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
if String.length(comment) <= max_size do
- {:ok, format_input(comment, [], [], "text/plain")}
+ {:ok, format_input(comment, "text/plain")}
else
{:error, "Comment must be up to #{max_size} characters"}
end
diff --git a/mix.exs b/mix.exs
index d78825769..5392d94d1 100644
--- a/mix.exs
+++ b/mix.exs
@@ -90,7 +90,10 @@ defp deps do
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test},
{:floki, "~> 0.20.0"},
{:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"},
- {:timex, "~> 3.5"}
+ {:timex, "~> 3.5"},
+ {:auto_linker,
+ git: "https://git.pleroma.social/pleroma/auto_linker.git",
+ ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}
]
end
diff --git a/mix.lock b/mix.lock
index 5ffaedd16..918702444 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,4 +1,5 @@
%{
+ "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd", [ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"]},
"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"},
diff --git a/test/formatter_test.exs b/test/formatter_test.exs
index f14077d25..7d8864bf4 100644
--- a/test/formatter_test.exs
+++ b/test/formatter_test.exs
@@ -21,22 +21,16 @@ test "turns hashtags into links" do
expected_text =
"I love #cofe and #2hu "
- tags = Formatter.parse_tags(text)
-
- assert expected_text ==
- Formatter.add_hashtag_links({[], text}, tags) |> Formatter.finalize()
+ assert {^expected_text, [], _tags} = Formatter.linkify(text)
end
test "does not turn html characters to tags" do
- text = "Fact #3: pleroma does what mastodon't"
+ text = "#fact_3: pleroma does what mastodon't"
expected_text =
- "Fact #3 : pleroma does what mastodon't"
+ "#fact_3 : pleroma does what mastodon't"
- tags = Formatter.parse_tags(text)
-
- assert expected_text ==
- Formatter.add_hashtag_links({[], text}, tags) |> Formatter.finalize()
+ assert {^expected_text, [], _tags} = Formatter.linkify(text)
end
end
@@ -47,79 +41,79 @@ test "turning urls into links" do
expected =
"Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla ."
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://mastodon.social/@lambadalambda"
expected =
"https://mastodon.social/@lambadalambda "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://mastodon.social:4000/@lambadalambda"
expected =
"https://mastodon.social:4000/@lambadalambda "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "@lambadalambda"
expected = "@lambadalambda"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "http://www.cs.vu.nl/~ast/intel/"
expected = "http://www.cs.vu.nl/~ast/intel/ "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://forum.zdoom.org/viewtopic.php?f=44&t=57087"
expected =
"https://forum.zdoom.org/viewtopic.php?f=44&t=57087 "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul"
expected =
"https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://www.google.co.jp/search?q=Nasim+Aghdam"
expected =
"https://www.google.co.jp/search?q=Nasim+Aghdam "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://en.wikipedia.org/wiki/Duff's_device"
expected =
"https://en.wikipedia.org/wiki/Duff's_device "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://pleroma.com https://pleroma.com/sucks"
expected =
"https://pleroma.com https://pleroma.com/sucks "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "xmpp:contact@hacktivis.me"
expected = "xmpp:contact@hacktivis.me "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text =
"magnet:?xt=urn:btih:7ec9d298e91d6e4394d1379caf073c77ff3e3136&tr=udp%3A%2F%2Fopentor.org%3A2710&tr=udp%3A%2F%2Ftracker.blackunicorn.xyz%3A6969&tr=udp%3A%2F%2Ftracker.ccc.de%3A80&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com"
expected = "#{text} "
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
end
end
@@ -136,12 +130,9 @@ test "gives a replacement for user links, using local nicknames in user links te
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
- mentions = Pleroma.Formatter.parse_mentions(text)
+ {text, mentions, []} = Formatter.linkify(text)
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
-
- assert length(subs) == 3
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
+ assert length(mentions) == 3
expected_text =
"@archaeme "
- assert expected_text == Formatter.finalize({subs, text})
+ assert expected_text == text
end
test "gives a replacement for user links when the user is using Osada" do
@@ -160,48 +151,35 @@ test "gives a replacement for user links when the user is using Osada" do
text = "@mike@osada.macgirvin.com test"
- mentions = Formatter.parse_mentions(text)
+ {text, mentions, []} = Formatter.linkify(text)
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
-
- assert length(subs) == 1
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
+ assert length(mentions) == 1
expected_text =
"@mike test"
- assert expected_text == Formatter.finalize({subs, text})
+ assert expected_text == text
end
test "gives a replacement for single-character local nicknames" do
text = "@o hi"
o = insert(:user, %{nickname: "o"})
- mentions = Formatter.parse_mentions(text)
+ {text, mentions, []} = Formatter.linkify(text)
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
-
- assert length(subs) == 1
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
+ assert length(mentions) == 1
expected_text =
"@o hi"
- assert expected_text == Formatter.finalize({subs, text})
+ assert expected_text == text
end
test "does not give a replacement for single-character local nicknames who don't exist" do
text = "@a hi"
- mentions = Formatter.parse_mentions(text)
-
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
-
- assert Enum.empty?(subs)
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
-
expected_text = "@a hi"
- assert expected_text == Formatter.finalize({subs, text})
+ assert {^expected_text, [] = _mentions, [] = _tags} = Formatter.linkify(text)
end
end
@@ -209,14 +187,14 @@ test "does not give a replacement for single-character local nicknames who don't
test "parses tags in the text" do
text = "Here's a #Test. Maybe these are #working or not. What about #漢字? And #は。"
- expected = [
+ expected_tags = [
{"#Test", "test"},
{"#working", "working"},
- {"#漢字", "漢字"},
- {"#は", "は"}
+ {"#は", "は"},
+ {"#漢字", "漢字"}
]
- assert Formatter.parse_tags(text) == expected
+ assert {_text, [], ^expected_tags} = Formatter.linkify(text)
end
end
@@ -230,15 +208,15 @@ test "it can parse mentions and return the relevant users" do
archaeme = insert(:user, %{nickname: "archaeme"})
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
- expected_result = [
- {"@gsimg", gsimg},
+ expected_mentions = [
{"@archaeme", archaeme},
{"@archaeme@archae.me", archaeme_remote},
- {"@o", o},
- {"@jimm", jimm}
+ {"@gsimg", gsimg},
+ {"@jimm", jimm},
+ {"@o", o}
]
- assert Formatter.parse_mentions(text) == expected_result
+ assert {_text, ^expected_mentions, []} = Formatter.linkify(text)
end
test "it adds cool emoji" do
@@ -281,22 +259,10 @@ test "it doesn't die when text is absent" do
assert Formatter.get_emoji(text) == []
end
- describe "/mentions_escape" do
- test "it returns text with escaped mention names" do
- text = """
- @a_breakin_glass@cybre.space
- (also, little voice inside my head thinking "maybe this will encourage people
- pronouncing it properly instead of saying _raKEWdo_ ")
- """
+ test "it escapes HTML in plain text" do
+ text = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1"
+ expected = "hello & world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1"
- escape_text = """
- @a\\_breakin\\_glass@cybre\\.space
- (also, little voice inside my head thinking \"maybe this will encourage people
- pronouncing it properly instead of saying _raKEWdo_ \")
- """
-
- mentions = [{"@a_breakin_glass@cybre.space", %{}}]
- assert Formatter.mentions_escape(text, mentions) == escape_text
- end
+ assert Formatter.html_escape(text, "text/plain") == expected
end
end
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index faed6b685..dc7b4c229 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -57,19 +57,19 @@ test "parses emoji from name and bio" do
assert expected == Utils.emoji_from_profile(user)
end
- describe "format_input/4" do
+ describe "format_input/3" do
test "works for bare text/plain" do
text = "hello world!"
expected = "hello world!"
- output = Utils.format_input(text, [], [], "text/plain")
+ {output, [], []} = Utils.format_input(text, "text/plain")
assert output == expected
text = "hello world!\n\nsecond paragraph!"
expected = "hello world! second paragraph!"
- output = Utils.format_input(text, [], [], "text/plain")
+ {output, [], []} = Utils.format_input(text, "text/plain")
assert output == expected
end
@@ -78,14 +78,14 @@ test "works for bare text/html" do
text = "hello world!
"
expected = "hello world!
"
- output = Utils.format_input(text, [], [], "text/html")
+ {output, [], []} = Utils.format_input(text, "text/html")
assert output == expected
text = "hello world!
\n\nsecond paragraph
"
expected = "hello world!
\n\nsecond paragraph
"
- output = Utils.format_input(text, [], [], "text/html")
+ {output, [], []} = Utils.format_input(text, "text/html")
assert output == expected
end
@@ -94,14 +94,32 @@ test "works for bare text/markdown" do
text = "**hello world**"
expected = "hello world
\n"
- output = Utils.format_input(text, [], [], "text/markdown")
+ {output, [], []} = Utils.format_input(text, "text/markdown")
assert output == expected
text = "**hello world**\n\n*another paragraph*"
expected = "hello world
\nanother paragraph
\n"
- output = Utils.format_input(text, [], [], "text/markdown")
+ {output, [], []} = Utils.format_input(text, "text/markdown")
+
+ assert output == expected
+ end
+
+ test "works for text/markdown with mentions" do
+ {:ok, user} =
+ UserBuilder.insert(%{nickname: "user__test", ap_id: "http://foo.com/user__test"})
+
+ text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*"
+
+ expected =
+ "hello world
\nanother @user__test and @user__test google.com paragraph
\n"
+
+ {output, _, _} = Utils.format_input(text, "text/markdown")
assert output == expected
end
From ed7fd6b47e93e0874e3d79f124b71693e43dbb2c Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Wed, 27 Feb 2019 03:08:03 +0300
Subject: [PATCH 012/184] Add missing docs and tests
---
docs/Admin-API.md | 201 ++++++++++++------
.../admin_api/admin_api_controller_test.exs | 35 +++
2 files changed, 168 insertions(+), 68 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 016444d58..508981d38 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -1,108 +1,173 @@
# Admin API
+
Authentication is required and the user must be an admin.
+## `/api/pleroma/admin/users`
+
+### List users
+
+- Method `GET`
+- Response:
+
+```JSON
+[
+ {
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
+ },
+ ...
+]
+```
+
## `/api/pleroma/admin/user`
+
### Remove a user
-* Method `DELETE`
-* Params:
- * `nickname`
-* Response: User’s nickname
+
+- Method `DELETE`
+- Params:
+ - `nickname`
+- Response: User’s nickname
+
### Create a user
-* Method: `POST`
-* Params:
- * `nickname`
- * `email`
- * `password`
-* Response: User’s nickname
-## `/api/pleroma/admin/users/tag`
-### Tag a list of users
-* Method: `PUT`
-* Params:
- * `nickname`
- * `tags`
-### Untag a list of users
-* Method: `DELETE`
-* Params:
- * `nickname`
- * `tags`
+- Method: `POST`
+- Params:
+ - `nickname`
+ - `email`
+ - `password`
+- Response: User’s nickname
+
+## `/api/pleroma/admin/users/:nickname/toggle_activation`
+
+### Toggle user activation
+
+- Method: `PATCH`
+- Params:
+ - `nickname`
+- Response: User’s object
-## `/api/pleroma/admin/permission_group/:nickname`
-### Get user user permission groups membership
-* Method: `GET`
-* Params: none
-* Response:
```JSON
{
- "is_moderator": bool,
- "is_admin": bool
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
+}
+```
+
+## `/api/pleroma/admin/users/tag`
+
+### Tag a list of users
+
+- Method: `PUT`
+- Params:
+ - `nickname`
+ - `tags`
+
+### Untag a list of users
+
+- Method: `DELETE`
+- Params:
+ - `nickname`
+ - `tags`
+
+## `/api/pleroma/admin/permission_group/:nickname`
+
+### Get user user permission groups membership
+
+- Method: `GET`
+- Params: none
+- Response:
+
+```JSON
+{
+ "is_moderator": bool,
+ "is_admin": bool
}
```
## `/api/pleroma/admin/permission_group/:nickname/:permission_group`
+
Note: Available `:permission_group` is currently moderator and admin. 404 is returned when the permission group doesn’t exist.
### Get user user permission groups membership
-* Method: `GET`
-* Params: none
-* Response:
+
+- Method: `GET`
+- Params: none
+- Response:
+
```JSON
{
- "is_moderator": bool,
- "is_admin": bool
+ "is_moderator": bool,
+ "is_admin": bool
}
```
+
### Add user in permission group
-* Method: `POST`
-* Params: none
-* Response:
- * On failure: ``{"error": "…"}``
- * On success: JSON of the ``user.info``
+
+- Method: `POST`
+- Params: none
+- Response:
+ - On failure: `{"error": "…"}`
+ - On success: JSON of the `user.info`
+
### Remove user from permission group
-* Method: `DELETE`
-* Params: none
-* Response:
- * On failure: ``{"error": "…"}``
- * On success: JSON of the ``user.info``
-* Note: An admin cannot revoke their own admin status.
+
+- Method: `DELETE`
+- Params: none
+- Response:
+ - On failure: `{"error": "…"}`
+ - On success: JSON of the `user.info`
+- Note: An admin cannot revoke their own admin status.
## `/api/pleroma/admin/activation_status/:nickname`
### Active or deactivate a user
-* Method: `PUT`
-* Params:
- * `nickname`
- * `status` BOOLEAN field, false value means deactivation.
+
+- Method: `PUT`
+- Params:
+ - `nickname`
+ - `status` BOOLEAN field, false value means deactivation.
## `/api/pleroma/admin/relay`
+
### Follow a Relay
-* Methods: `POST`
-* Params:
- * `relay_url`
-* Response:
- * On success: URL of the followed relay
+
+- Methods: `POST`
+- Params:
+ - `relay_url`
+- Response:
+ - On success: URL of the followed relay
+
### Unfollow a Relay
-* Methods: `DELETE`
-* Params:
- * `relay_url`
-* Response:
- * On success: URL of the unfollowed relay
+
+- Methods: `DELETE`
+- Params:
+ - `relay_url`
+- Response:
+ - On success: URL of the unfollowed relay
## `/api/pleroma/admin/invite_token`
+
### Get a account registeration invite token
-* Methods: `GET`
-* Params: none
-* Response: invite token (base64 string)
+
+- Methods: `GET`
+- Params: none
+- Response: invite token (base64 string)
## `/api/pleroma/admin/email_invite`
+
### Sends registration invite via email
-* Methods: `POST`
-* Params:
- * `email`
- * `name`, optionnal
+
+- Methods: `POST`
+- Params:
+ - `email`
+ - `name`, optionnal
## `/api/pleroma/admin/password_reset`
+
### Get a password reset token for a given nickname
-* Methods: `GET`
-* Params: none
-* Response: password reset token (base64 string)
+
+- Methods: `GET`
+- Params: none
+- Response: password reset token (base64 string)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 9fbaaba39..f6ae16844 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -330,4 +330,39 @@ test "/api/pleroma/admin/password_reset" do
assert conn.status == 200
end
+
+ test "GET /api/pleroma/admin/users" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users")
+
+ assert json_response(conn, 200) == [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ end
+
+ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
+
+ assert json_response(conn, 200) ==
+ %{
+ "deactivated" => !user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ end
end
From 5d961d536cd190c8201d53624680a6f3384ffd9b Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn
Date: Wed, 27 Feb 2019 15:40:30 +0700
Subject: [PATCH 013/184] fix formatter
---
lib/pleroma/formatter.ex | 4 ++++
lib/pleroma/web/common_api/utils.ex | 2 +-
test/web/common_api/common_api_utils_test.exs | 18 +++++++++++++++---
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index 51d08c5ee..048c032ed 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -91,6 +91,10 @@ def get_emoji(text) when is_binary(text) do
def get_emoji(_), do: []
+ def html_escape({text, mentions, hashtags}, type) do
+ {html_escape(text, type), mentions, hashtags}
+ end
+
def html_escape(text, "text/html") do
HTML.filter_tags(text)
end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 20123854d..e4b9102c5 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -186,9 +186,9 @@ def format_input(text, "text/markdown", options) do
options = Keyword.put(options, :mentions_escape, true)
text
- |> Formatter.html_escape("text/html")
|> Formatter.linkify(options)
|> (fn {text, mentions, tags} -> {Earmark.as_html!(text), mentions, tags} end).()
+ |> Formatter.html_escape("text/html")
end
def make_note_data(
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index dc7b4c229..684f2a23f 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -104,6 +104,18 @@ test "works for bare text/markdown" do
{output, [], []} = Utils.format_input(text, "text/markdown")
assert output == expected
+
+ text = """
+ > cool quote
+
+ by someone
+ """
+
+ expected = "cool quote
\n \nby someone
\n"
+
+ {output, [], []} = Utils.format_input(text, "text/markdown")
+
+ assert output == expected
end
test "works for text/markdown with mentions" do
@@ -113,11 +125,11 @@ test "works for text/markdown with mentions" do
text = "**hello world**\n\n*another @user__test and @user__test google.com paragraph*"
expected =
- "hello world
\nanother @user__test and @user__test google.com paragraph
\n"
+ }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@user__test google.com paragraph
\n"
{output, _, _} = Utils.format_input(text, "text/markdown")
From 153664096255208055ae2e0b31ea20238ad540b2 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Wed, 27 Feb 2019 13:01:10 +0000
Subject: [PATCH 014/184] mastodon api: embed relationship card under account
card for Pleroma FE convenience
---
.../web/mastodon_api/views/account_view.ex | 11 +++-
test/web/mastodon_api/account_view_test.exs | 66 ++++++++++++++++++-
2 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 8fdefdebd..c32f27be2 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -32,7 +32,11 @@ def render("mention.json", %{user: user}) do
}
end
- def render("relationship.json", %{user: user, target: target}) do
+ def render("relationship.json", %{user: nil, target: _target}) do
+ %{}
+ end
+
+ def render("relationship.json", %{user: %User{} = user, target: %User{} = target}) do
follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target)
requested =
@@ -85,6 +89,8 @@ defp do_render("account.json", %{user: user} = opts) do
bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
+ relationship = render("relationship.json", %{user: opts[:for], target: user})
+
%{
id: to_string(user.id),
username: username_from_nickname(user.nickname),
@@ -115,7 +121,8 @@ defp do_render("account.json", %{user: user} = opts) do
confirmation_pending: user_info.confirmation_pending,
tags: user.tags,
is_moderator: user.info.is_moderator,
- is_admin: user.info.is_admin
+ is_admin: user.info.is_admin,
+ relationship: relationship
}
}
end
diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs
index f8cd68173..6be66ef63 100644
--- a/test/web/mastodon_api/account_view_test.exs
+++ b/test/web/mastodon_api/account_view_test.exs
@@ -63,7 +63,8 @@ test "Represent a user account" do
confirmation_pending: false,
tags: [],
is_admin: false,
- is_moderator: false
+ is_moderator: false,
+ relationship: %{}
}
}
@@ -106,7 +107,8 @@ test "Represent a Service(bot) account" do
confirmation_pending: false,
tags: [],
is_admin: false,
- is_moderator: false
+ is_moderator: false,
+ relationship: %{}
}
}
@@ -148,4 +150,64 @@ test "represent a relationship" do
assert expected == AccountView.render("relationship.json", %{user: user, target: other_user})
end
+
+ test "represent an embedded relationship" do
+ user =
+ insert(:user, %{
+ info: %{note_count: 5, follower_count: 3, source_data: %{"type" => "Service"}},
+ nickname: "shp@shitposter.club",
+ inserted_at: ~N[2017-08-15 15:47:06.597036]
+ })
+
+ other_user = insert(:user)
+
+ {:ok, other_user} = User.follow(other_user, user)
+ {:ok, other_user} = User.block(other_user, user)
+
+ expected = %{
+ id: to_string(user.id),
+ username: "shp",
+ acct: user.nickname,
+ display_name: user.name,
+ locked: false,
+ created_at: "2017-08-15T15:47:06.000Z",
+ followers_count: 3,
+ following_count: 0,
+ statuses_count: 5,
+ note: user.bio,
+ url: user.ap_id,
+ avatar: "http://localhost:4001/images/avi.png",
+ avatar_static: "http://localhost:4001/images/avi.png",
+ header: "http://localhost:4001/images/banner.png",
+ header_static: "http://localhost:4001/images/banner.png",
+ emojis: [],
+ fields: [],
+ bot: true,
+ source: %{
+ note: "",
+ privacy: "public",
+ sensitive: false
+ },
+ pleroma: %{
+ confirmation_pending: false,
+ tags: [],
+ is_admin: false,
+ is_moderator: false,
+ relationship: %{
+ id: to_string(user.id),
+ following: false,
+ followed_by: false,
+ blocking: true,
+ muting: false,
+ muting_notifications: false,
+ requested: false,
+ domain_blocking: false,
+ showing_reblogs: false,
+ endorsed: false
+ }
+ }
+ }
+
+ assert expected == AccountView.render("account.json", %{user: user, for: other_user})
+ end
end
From 8d8cb08f94490299bfc7fe97381a34e4a7a095a9 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 14:51:07 +0100
Subject: [PATCH 015/184] Add follow request test.
---
test/user_test.exs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/test/user_test.exs b/test/user_test.exs
index 0b1c39ecf..cbe4693fc 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -50,6 +50,20 @@ test "ap_followers returns the followers collection for the user" do
assert expected_followers_collection == User.ap_followers(user)
end
+ test "returns all pending follow requests" do
+ unlocked = insert(:user)
+ locked = insert(:user, %{info: %{locked: true}})
+ follower = insert(:user)
+
+ Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => unlocked.id})
+ Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => locked.id})
+
+ assert {:ok, []} = User.get_follow_requests(unlocked)
+ assert {:ok, [activity]} = User.get_follow_requests(locked)
+
+ assert activity
+ end
+
test "follow_all follows mutliple users" do
user = insert(:user)
followed_zero = insert(:user)
From b24cc44e8d1e1b29cdeb916f192e30303a55ff5d Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 15:01:54 +0100
Subject: [PATCH 016/184] Follower requests: Utilize object index.
Closes #677
---
lib/pleroma/user.ex | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 01d532ab3..c5085fa82 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -613,9 +613,10 @@ def get_follow_requests_query(%User{} = user) do
),
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
a.data,
- ^%{"object" => user.ap_id}
+ a.data,
+ ^user.ap_id
)
)
end
From c4235f96bde49def1fb6927ba79a49a0f75cd60a Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 16:37:42 +0100
Subject: [PATCH 017/184] Add `with_muted` param.
---
docs/Differences-in-MastodonAPI-Responses.md | 4 ++++
lib/pleroma/web/activity_pub/activity_pub.ex | 2 ++
test/web/activity_pub/activity_pub_test.exs | 7 +++++++
3 files changed, 13 insertions(+)
diff --git a/docs/Differences-in-MastodonAPI-Responses.md b/docs/Differences-in-MastodonAPI-Responses.md
index f6a5b6461..3026e1173 100644
--- a/docs/Differences-in-MastodonAPI-Responses.md
+++ b/docs/Differences-in-MastodonAPI-Responses.md
@@ -9,3 +9,7 @@ Pleroma uses 128-bit ids as opposed to Mastodon's 64 bits. However just like Mas
## Attachment cap
Some apps operate under the assumption that no more than 4 attachments can be returned or uploaded. Pleroma however does not enforce any limits on attachment count neither when returning the status object nor when posting.
+
+## Timelines
+
+Adding the parameter `with_muted=true` to the timeline queries will also return activities by muted (not by blocked!) users.
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index cc255cc9e..52404c7e5 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -602,6 +602,8 @@ defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or
defp restrict_reblogs(query, _), do: query
+ defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
+
defp restrict_muted(query, %{"muting_user" => %User{info: info}}) do
mutes = info.mutes
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 11262c523..ac3a565de 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -291,6 +291,13 @@ test "doesn't return muted activities" do
assert Enum.member?(activities, activity_three)
refute Enum.member?(activities, activity_one)
+ # Calling with 'with_muted' will deliver muted activities, too.
+ activities = ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
+
+ assert Enum.member?(activities, activity_two)
+ assert Enum.member?(activities, activity_three)
+ assert Enum.member?(activities, activity_one)
+
{:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
From c1ae495878cc95d09a051cc56e2bf7dc7ed0a032 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 16:46:47 +0100
Subject: [PATCH 018/184] Add user muted status info to MastodonAPI.
---
lib/pleroma/user.ex | 1 +
.../web/mastodon_api/views/status_view.ex | 2 +-
test/web/mastodon_api/status_view_test.exs | 16 ++++++++++++++++
3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 01d532ab3..3a8a51e33 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -960,6 +960,7 @@ def unblock(blocker, %{ap_id: ap_id}) do
update_and_set_cache(cng)
end
+ def mutes?(nil, _), do: false
def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info.mutes, ap_id)
def blocks?(user, %{ap_id: ap_id}) do
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index b90e4252a..3468c0e1c 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -168,7 +168,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
reblogged: present?(repeated),
favourited: present?(favorited),
bookmarked: present?(bookmarked),
- muted: CommonAPI.thread_muted?(user, activity),
+ muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user),
pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: object["summary"] || "",
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index 3412a6be2..351dbf673 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -126,6 +126,22 @@ test "a note activity" do
assert status == expected
end
+ test "tells if the message is muted for some reason" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, user} = User.mute(user, other_user)
+
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
+ status = StatusView.render("status.json", %{activity: activity})
+
+ assert status.muted == false
+
+ status = StatusView.render("status.json", %{activity: activity, for: user})
+
+ assert status.muted == true
+ end
+
test "a reply" do
note = insert(:note_activity)
user = insert(:user)
From 9ade1242c20acae5d27785deb833b453628b12ee Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 16:52:03 +0100
Subject: [PATCH 019/184] Add user muted status info to twitterapi.
---
.../web/twitter_api/views/activity_view.ex | 4 +++-
.../twitter_api/views/activity_view_test.exs | 19 ++++++++++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 661022afa..02ca4ee42 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.TwitterAPI.ActivityView
@@ -309,7 +310,8 @@ def render(
"visibility" => StatusView.get_visibility(object),
"summary" => summary,
"summary_html" => summary |> Formatter.emojify(object["emoji"]),
- "card" => card
+ "card" => card,
+ "muted" => CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user)
}
end
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index 4f854ecaa..0a5384f34 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -56,6 +56,22 @@ test "tries to get a user by nickname if fetching by ap_id doesn't work" do
assert result["user"]["id"] == user.id
end
+ test "tells if the message is muted for some reason" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, user} = User.mute(user, other_user)
+
+ {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
+ status = ActivityView.render("activity.json", %{activity: activity})
+
+ assert status["muted"] == false
+
+ status = ActivityView.render("activity.json", %{activity: activity, for: user})
+
+ assert status["muted"] == true
+ end
+
test "a create activity with a html status" do
text = """
#Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg
@@ -149,7 +165,8 @@ test "a create activity with a note" do
"uri" => activity.data["object"]["id"],
"user" => UserView.render("show.json", %{user: user}),
"visibility" => "direct",
- "card" => nil
+ "card" => nil,
+ "muted" => false
}
assert result == expected
From bbbdbec4fd8f14aa039d7f4a42215544cd6e4932 Mon Sep 17 00:00:00 2001
From: lain
Date: Wed, 27 Feb 2019 17:24:51 +0100
Subject: [PATCH 020/184] Remove parts of the old activity view.
Not used anymore.
---
.../representers/activity_representer.ex | 247 +-----------------
.../activity_representer_test.exs | 43 +--
2 files changed, 6 insertions(+), 284 deletions(-)
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 192ab7334..55c612ddd 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -6,247 +6,10 @@
# THIS MODULE IS DEPRECATED! DON'T USE IT!
# USE THE Pleroma.Web.TwitterAPI.Views.ActivityView MODULE!
defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
- use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
- alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
- alias Pleroma.Activity
- alias Pleroma.Formatter
- alias Pleroma.HTML
- alias Pleroma.User
- alias Pleroma.Web.TwitterAPI.ActivityView
- alias Pleroma.Web.TwitterAPI.TwitterAPI
- alias Pleroma.Web.TwitterAPI.UserView
- alias Pleroma.Web.CommonAPI.Utils
- alias Pleroma.Web.MastodonAPI.StatusView
-
- defp user_by_ap_id(user_list, ap_id) do
- Enum.find(user_list, fn %{ap_id: user_id} -> ap_id == user_id end)
- end
-
- def to_map(
- %Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} =
- activity,
- %{users: users, announced_activity: announced_activity} = opts
- ) do
- user = user_by_ap_id(users, actor)
- created_at = created_at |> Utils.date_to_asctime()
-
- text = "#{user.nickname} retweeted a status."
-
- announced_user = user_by_ap_id(users, announced_activity.data["actor"])
- retweeted_status = to_map(announced_activity, Map.merge(%{user: announced_user}, opts))
-
- %{
- "id" => activity.id,
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "statusnet_html" => text,
- "text" => text,
- "is_local" => activity.local,
- "is_post_verb" => false,
- "uri" => "tag:#{activity.data["id"]}:objectType=note",
- "created_at" => created_at,
- "retweeted_status" => retweeted_status,
- "statusnet_conversation_id" => conversation_id(announced_activity),
- "external_url" => activity.data["id"],
- "activity_type" => "repeat"
- }
- end
-
- def to_map(
- %Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
- %{user: user, liked_activity: liked_activity} = opts
- ) do
- created_at = created_at |> Utils.date_to_asctime()
-
- text = "#{user.nickname} favorited a status."
-
- %{
- "id" => activity.id,
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "statusnet_html" => text,
- "text" => text,
- "is_local" => activity.local,
- "is_post_verb" => false,
- "uri" => "tag:#{activity.data["id"]}:objectType=Favourite",
- "created_at" => created_at,
- "in_reply_to_status_id" => liked_activity.id,
- "external_url" => activity.data["id"],
- "activity_type" => "like"
- }
- end
-
- def to_map(
- %Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity,
- %{user: user} = opts
- ) do
- created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at)
- created_at = created_at |> Utils.date_to_asctime()
-
- followed = User.get_cached_by_ap_id(followed_id)
- text = "#{user.nickname} started following #{followed.nickname}"
-
- %{
- "id" => activity.id,
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "attentions" => [],
- "statusnet_html" => text,
- "text" => text,
- "is_local" => activity.local,
- "is_post_verb" => false,
- "created_at" => created_at,
- "in_reply_to_status_id" => nil,
- "external_url" => activity.data["id"],
- "activity_type" => "follow"
- }
- end
-
- # TODO:
- # Make this more proper. Just a placeholder to not break the frontend.
- def to_map(
- %Activity{
- data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity}
- } = activity,
- %{user: user} = opts
- ) do
- created_at = created_at |> Utils.date_to_asctime()
-
- text = "#{user.nickname} undid the action at #{undid_activity["id"]}"
-
- %{
- "id" => activity.id,
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "attentions" => [],
- "statusnet_html" => text,
- "text" => text,
- "is_local" => activity.local,
- "is_post_verb" => false,
- "created_at" => created_at,
- "in_reply_to_status_id" => nil,
- "external_url" => activity.data["id"],
- "activity_type" => "undo"
- }
- end
-
- def to_map(
- %Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _}} =
- activity,
- %{user: user} = opts
- ) do
- created_at = created_at |> Utils.date_to_asctime()
-
- %{
- "id" => activity.id,
- "uri" => activity.data["object"],
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "attentions" => [],
- "statusnet_html" => "deleted notice {{tag",
- "text" => "deleted notice {{tag",
- "is_local" => activity.local,
- "is_post_verb" => false,
- "created_at" => created_at,
- "in_reply_to_status_id" => nil,
- "external_url" => activity.data["id"],
- "activity_type" => "delete"
- }
- end
-
- def to_map(
- %Activity{data: %{"object" => %{"content" => _content} = object}} = activity,
- %{user: user} = opts
- ) do
- created_at = object["published"] |> Utils.date_to_asctime()
- like_count = object["like_count"] || 0
- announcement_count = object["announcement_count"] || 0
- favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
- repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
- pinned = activity.id in user.info.pinned_activities
-
- mentions = opts[:mentioned] || []
-
- attentions =
- []
- |> Utils.maybe_notify_to_recipients(activity)
- |> Utils.maybe_notify_mentioned_recipients(activity)
- |> Enum.map(fn ap_id -> Enum.find(mentions, fn user -> ap_id == user.ap_id end) end)
- |> Enum.filter(& &1)
- |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
-
- conversation_id = conversation_id(activity)
-
- tags = activity.data["object"]["tag"] || []
- possibly_sensitive = activity.data["object"]["sensitive"] || Enum.member?(tags, "nsfw")
-
- tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
-
- {_summary, content} = ActivityView.render_content(object)
-
- html =
- HTML.filter_tags(content, User.html_filter_policy(opts[:for]))
- |> Formatter.emojify(object["emoji"])
-
- attachments = object["attachment"] || []
-
- reply_parent = Activity.get_in_reply_to_activity(activity)
-
- reply_user = reply_parent && User.get_cached_by_ap_id(reply_parent.actor)
-
- summary = HTML.strip_tags(object["summary"])
-
- card =
- StatusView.render(
- "card.json",
- Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- )
-
- %{
- "id" => activity.id,
- "uri" => activity.data["object"]["id"],
- "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
- "statusnet_html" => html,
- "text" => HTML.strip_tags(content),
- "is_local" => activity.local,
- "is_post_verb" => true,
- "created_at" => created_at,
- "in_reply_to_status_id" => object["inReplyToStatusId"],
- "in_reply_to_screen_name" => reply_user && reply_user.nickname,
- "in_reply_to_profileurl" => User.profile_url(reply_user),
- "in_reply_to_ostatus_uri" => reply_user && reply_user.ap_id,
- "in_reply_to_user_id" => reply_user && reply_user.id,
- "statusnet_conversation_id" => conversation_id,
- "attachments" => attachments |> ObjectRepresenter.enum_to_list(opts),
- "attentions" => attentions,
- "fave_num" => like_count,
- "repeat_num" => announcement_count,
- "favorited" => to_boolean(favorited),
- "repeated" => to_boolean(repeated),
- "pinned" => pinned,
- "external_url" => object["external_url"] || object["id"],
- "tags" => tags,
- "activity_type" => "post",
- "possibly_sensitive" => possibly_sensitive,
- "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object),
- "summary" => summary,
- "summary_html" => summary |> Formatter.emojify(object["emoji"]),
- "card" => card
- }
- end
-
- def conversation_id(activity) do
- with context when not is_nil(context) <- activity.data["context"] do
- TwitterAPI.context_to_conversation_id(context)
- else
- _e -> nil
- end
- end
-
- defp to_boolean(false) do
- false
- end
-
- defp to_boolean(nil) do
- false
- end
-
- defp to_boolean(_) do
- true
+ def to_map(activity, opts) do
+ Pleroma.Web.TwitterAPI.ActivityView.render(
+ "activity.json",
+ Map.put(opts, :activity, activity)
+ )
end
end
diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs
index 365c7f659..0e554623c 100644
--- a/test/web/twitter_api/representers/activity_representer_test.exs
+++ b/test/web/twitter_api/representers/activity_representer_test.exs
@@ -13,36 +13,6 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
alias Pleroma.Web.TwitterAPI.UserView
import Pleroma.Factory
- test "an announce activity" do
- user = insert(:user)
- note_activity = insert(:note_activity)
- activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"])
- object = Object.get_by_ap_id(note_activity.data["object"]["id"])
-
- {:ok, announce_activity, _object} = ActivityPub.announce(user, object)
- note_activity = Activity.get_by_ap_id(note_activity.data["id"])
-
- status =
- ActivityRepresenter.to_map(announce_activity, %{
- users: [user, activity_actor],
- announced_activity: note_activity,
- for: user
- })
-
- assert status["id"] == announce_activity.id
- assert status["user"] == UserView.render("show.json", %{user: user, for: user})
-
- retweeted_status =
- ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user})
-
- assert retweeted_status["repeated"] == true
- assert retweeted_status["id"] == note_activity.id
- assert status["statusnet_conversation_id"] == retweeted_status["statusnet_conversation_id"]
-
- assert status["retweeted_status"] == retweeted_status
- assert status["activity_type"] == "repeat"
- end
-
test "a like activity" do
user = insert(:user)
note_activity = insert(:note_activity)
@@ -168,6 +138,7 @@ test "an activity" do
"uri" => activity.data["object"]["id"],
"visibility" => "direct",
"card" => nil,
+ "muted" => false,
"summary" => "2hu :2hu:",
"summary_html" =>
"2hu "
@@ -180,18 +151,6 @@ test "an activity" do
}) == expected_status
end
- test "an undo for a follow" do
- follower = insert(:user)
- followed = insert(:user)
-
- {:ok, _follow} = ActivityPub.follow(follower, followed)
- {:ok, unfollow} = ActivityPub.unfollow(follower, followed)
-
- map = ActivityRepresenter.to_map(unfollow, %{user: follower})
- assert map["is_post_verb"] == false
- assert map["activity_type"] == "undo"
- end
-
test "a delete activity" do
object = insert(:note)
user = User.get_by_ap_id(object.data["actor"])
From 2883f75a3a25599c6217460133578cddcd34ebb4 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Thu, 28 Feb 2019 01:11:56 +0300
Subject: [PATCH 021/184] Add pagination to users admin API
---
lib/pleroma/user.ex | 21 ++++++++++++++++---
.../web/admin_api/admin_api_controller.ex | 20 +++++++++++++-----
.../web/twitter_api/views/user_view.ex | 9 +++++---
.../admin_api/admin_api_controller_test.exs | 20 +++++++++++-------
4 files changed, 51 insertions(+), 19 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 01d532ab3..80e4ae296 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -772,10 +772,25 @@ def search(query, resolve \\ false, for_user \\ nil) do
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
end
- def all_except_one(user) do
- query = from(u in User, where: u.id != ^user.id)
+ def all_except_one(user, page, page_size) do
+ from(
+ u in User,
+ where: u.id != ^user.id,
+ limit: ^page_size,
+ offset: ^((page - 1) * page_size),
+ order_by: u.id
+ )
+ |> Repo.all()
+ end
- Repo.all(query)
+ def count_all_except_one(user) do
+ query =
+ from(
+ u in User,
+ where: u.id != ^user.id
+ )
+
+ Repo.aggregate(query, :count, :id)
end
defp do_search(subquery, for_user, options \\ []) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index ef72509fe..d75b7e7e7 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -3,6 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.AdminAPIController do
+ @users_page_size 50
+
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
@@ -61,11 +63,19 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
do: json_response(conn, :no_content, "")
end
- def list_users(%{assigns: %{user: admin}} = conn, _data) do
- users = User.all_except_one(admin)
-
- conn
- |> json(UserView.render("index_for_admin.json", %{users: users}))
+ def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
+ with {page, _} <- Integer.parse(page_string),
+ users <- User.all_except_one(admin, page, @users_page_size),
+ count <- User.count_all_except_one(admin),
+ do:
+ conn
+ |> json(
+ UserView.render("index_for_admin.json", %{
+ users: users,
+ count: count,
+ page_size: @users_page_size
+ })
+ )
end
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index c5034cf36..e8514d3ba 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -27,9 +27,12 @@ def render("user.json", %{user: user = %User{}} = assigns) do
else: %{}
end
- def render("index_for_admin.json", %{users: users} = opts) do
- users
- |> render_many(UserView, "show_for_admin.json", opts)
+ def render("index_for_admin.json", %{users: users, count: count, page_size: page_size} = opts) do
+ %{
+ users: render_many(users, UserView, "show_for_admin.json", opts),
+ count: count,
+ page_size: page_size
+ }
end
def render("show_for_admin.json", %{user: user}) do
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index f6ae16844..1b0a2f5be 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -338,15 +338,19 @@ test "GET /api/pleroma/admin/users" do
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users")
+ |> get("/api/pleroma/admin/users?page=1")
- assert json_response(conn, 200) == [
- %{
- "deactivated" => user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- ]
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
end
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
From 6b11011039dca5090c3a7b7b2a01f32b666be380 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Thu, 28 Feb 2019 08:31:33 +0300
Subject: [PATCH 022/184] Added deactivated to the user view
---
lib/pleroma/web/twitter_api/views/user_view.ex | 7 +++++++
test/web/twitter_api/views/user_view_test.exs | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index c5034cf36..22f33e0b5 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -132,6 +132,7 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do
"confirmation_pending" => user_info.confirmation_pending,
"tags" => user.tags
}
+ |> maybe_with_activation_status(user, for_user)
|> maybe_with_follow_request_count(user, for_user)
}
@@ -148,6 +149,12 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do
end
end
+ defp maybe_with_activation_status(data, user, %User{info: %{is_admin: true}}) do
+ Map.put(data, "deactivated", user.info.deactivated)
+ end
+
+ defp maybe_with_activation_status(data, _, _), do: data
+
defp maybe_with_follow_request_count(data, %User{id: id, info: %{locked: true}} = user, %User{
id: id
}) do
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 95e52ca46..114f24a1c 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -239,6 +239,13 @@ test "An admin with hidden role for another user", %{user: user} do
assert represented["role"] == nil
end
+ test "A regular user for the admin", %{user: user} do
+ admin = insert(:user, %{info: %{is_admin: true}})
+ represented = UserView.render("show.json", %{user: user, for: admin})
+
+ assert represented["pleroma"]["deactivated"] == false
+ end
+
test "A blocked user for the blocker" do
user = insert(:user)
blocker = insert(:user)
From b6f915313f59223002a0eff88c1eefb00ca5c8f3 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Thu, 28 Feb 2019 13:00:54 +0300
Subject: [PATCH 023/184] Made auth customization be runtime-configurable.
---
lib/pleroma/web/auth/database_authenticator.ex | 14 ++++++++------
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
lib/pleroma/web/web.ex | 6 +++++-
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/web/auth/database_authenticator.ex b/lib/pleroma/web/auth/database_authenticator.ex
index 02a16b634..e78068b03 100644
--- a/lib/pleroma/web/auth/database_authenticator.ex
+++ b/lib/pleroma/web/auth/database_authenticator.ex
@@ -5,14 +5,16 @@
defmodule Pleroma.Web.Auth.DatabaseAuthenticator do
alias Pleroma.User
- @implementation Pleroma.Config.get(
- Pleroma.Web.Auth.DatabaseAuthenticator,
- Pleroma.Web.Auth.PleromaDatabaseAuthenticator
- )
+ def implementation do
+ Pleroma.Config.get(
+ Pleroma.Web.Auth.DatabaseAuthenticator,
+ Pleroma.Web.Auth.PleromaDatabaseAuthenticator
+ )
+ end
@callback get_user(Plug.Conn.t()) :: {:ok, User.t()} | {:error, any()}
- defdelegate get_user(plug), to: @implementation
+ def get_user(plug), do: implementation().get_user(plug)
@callback handle_error(Plug.Conn.t(), any()) :: any()
- defdelegate handle_error(plug, error), to: @implementation
+ def handle_error(plug, error), do: implementation().handle_error(plug, error)
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 02c0babd2..5c2b0507c 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -25,7 +25,7 @@ def authorize(conn, params) do
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
- template = Application.get_env(:pleroma, :auth_template, "show.html")
+ template = Pleroma.Config.get(:auth_template, "show.html")
render(conn, template, %{
response_type: params["response_type"],
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index 4bf07a6ef..66813e4dd 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -27,7 +27,11 @@ def controller do
import Pleroma.Web.Gettext
import Pleroma.Web.Router.Helpers
- plug(:put_layout, Application.get_env(:pleroma, :app_layout, "app.html"))
+ plug(:set_put_layout)
+
+ defp set_put_layout(conn, _) do
+ put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
+ end
end
end
From 4e77f68414c1dd6a906d1d9b6b78916db5c213d5 Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Thu, 28 Feb 2019 13:58:58 +0300
Subject: [PATCH 024/184] Added `auth_template/0` to DatabaseAuthenticator.
---
lib/pleroma/web/auth/database_authenticator.ex | 5 +++++
lib/pleroma/web/auth/pleroma_database_authenticator.ex | 2 ++
lib/pleroma/web/oauth/oauth_controller.ex | 4 +---
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/auth/database_authenticator.ex b/lib/pleroma/web/auth/database_authenticator.ex
index e78068b03..494f28f23 100644
--- a/lib/pleroma/web/auth/database_authenticator.ex
+++ b/lib/pleroma/web/auth/database_authenticator.ex
@@ -17,4 +17,9 @@ def get_user(plug), do: implementation().get_user(plug)
@callback handle_error(Plug.Conn.t(), any()) :: any()
def handle_error(plug, error), do: implementation().handle_error(plug, error)
+
+ @callback auth_template() :: String.t() | nil
+ def auth_template do
+ implementation().auth_template() || Pleroma.Config.get(:auth_template, "show.html")
+ end
end
diff --git a/lib/pleroma/web/auth/pleroma_database_authenticator.ex b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
index 39aa1a586..0780388bc 100644
--- a/lib/pleroma/web/auth/pleroma_database_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_database_authenticator.ex
@@ -23,4 +23,6 @@ def get_user(%Plug.Conn{} = conn) do
def handle_error(%Plug.Conn{} = _conn, error) do
error
end
+
+ def auth_template, do: nil
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 5c2b0507c..99346f399 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -25,9 +25,7 @@ def authorize(conn, params) do
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
- template = Pleroma.Config.get(:auth_template, "show.html")
-
- render(conn, template, %{
+ render(conn, DatabaseAuthenticator.auth_template(), %{
response_type: params["response_type"],
client_id: params["client_id"],
available_scopes: available_scopes,
From 3281a3f074f8aac6a05a24cc2eee4e5bad2275bd Mon Sep 17 00:00:00 2001
From: Ivan Tashkinov
Date: Thu, 28 Feb 2019 14:12:41 +0300
Subject: [PATCH 025/184] Renamed *DatabaseAuthenticator to *Authenticator.
---
.../auth/{database_authenticator.ex => authenticator.ex} | 6 +++---
...database_authenticator.ex => pleroma_authenticator.ex} | 4 ++--
lib/pleroma/web/oauth/oauth_controller.ex | 8 ++++----
3 files changed, 9 insertions(+), 9 deletions(-)
rename lib/pleroma/web/auth/{database_authenticator.ex => authenticator.ex} (81%)
rename lib/pleroma/web/auth/{pleroma_database_authenticator.ex => pleroma_authenticator.ex} (85%)
diff --git a/lib/pleroma/web/auth/database_authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
similarity index 81%
rename from lib/pleroma/web/auth/database_authenticator.ex
rename to lib/pleroma/web/auth/authenticator.ex
index 494f28f23..82267c595 100644
--- a/lib/pleroma/web/auth/database_authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -2,13 +2,13 @@
# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.Auth.DatabaseAuthenticator do
+defmodule Pleroma.Web.Auth.Authenticator do
alias Pleroma.User
def implementation do
Pleroma.Config.get(
- Pleroma.Web.Auth.DatabaseAuthenticator,
- Pleroma.Web.Auth.PleromaDatabaseAuthenticator
+ Pleroma.Web.Auth.Authenticator,
+ Pleroma.Web.Auth.PleromaAuthenticator
)
end
diff --git a/lib/pleroma/web/auth/pleroma_database_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
similarity index 85%
rename from lib/pleroma/web/auth/pleroma_database_authenticator.ex
rename to lib/pleroma/web/auth/pleroma_authenticator.ex
index 0780388bc..3cc19af01 100644
--- a/lib/pleroma/web/auth/pleroma_database_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -2,11 +2,11 @@
# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.Auth.PleromaDatabaseAuthenticator do
+defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Pleroma.User
alias Comeonin.Pbkdf2
- @behaviour Pleroma.Web.Auth.DatabaseAuthenticator
+ @behaviour Pleroma.Web.Auth.Authenticator
def get_user(%Plug.Conn{} = conn) do
%{"authorization" => %{"name" => name, "password" => password}} = conn.params
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 99346f399..b16e3b2a7 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
- alias Pleroma.Web.Auth.DatabaseAuthenticator
+ alias Pleroma.Web.Auth.Authenticator
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.OAuth.App
@@ -25,7 +25,7 @@ def authorize(conn, params) do
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
- render(conn, DatabaseAuthenticator.auth_template(), %{
+ render(conn, Authenticator.auth_template(), %{
response_type: params["response_type"],
client_id: params["client_id"],
available_scopes: available_scopes,
@@ -43,7 +43,7 @@ def create_authorization(conn, %{
"redirect_uri" => redirect_uri
} = auth_params
}) do
- with {_, {:ok, %User{} = user}} <- {:get_user, DatabaseAuthenticator.get_user(conn)},
+ with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
scopes <- oauth_scopes(auth_params, []),
@@ -96,7 +96,7 @@ def create_authorization(conn, %{
|> authorize(auth_params)
error ->
- DatabaseAuthenticator.handle_error(conn, error)
+ Authenticator.handle_error(conn, error)
end
end
From 72b7a0797ec42a021f4f8f50dce859fb0f12bf75 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Thu, 28 Feb 2019 17:43:09 +0300
Subject: [PATCH 026/184] Use Mastodon API views in Admin API
---
.../web/admin_api/admin_api_controller.ex | 6 ++---
.../mastodon_api/views/admin/account_view.ex | 25 +++++++++++++++++++
.../web/twitter_api/views/user_view.ex | 17 -------------
3 files changed, 28 insertions(+), 20 deletions(-)
create mode 100644 lib/pleroma/web/mastodon_api/views/admin/account_view.ex
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index d75b7e7e7..d8e3d57e1 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
- alias Pleroma.Web.TwitterAPI.UserView
+ alias Pleroma.Web.MastodonAPI.Admin.AccountView
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
@@ -50,7 +50,7 @@ def user_toggle_activation(conn, %{"nickname" => nickname}) do
{:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
conn
- |> json(UserView.render("show_for_admin.json", %{user: updated_user}))
+ |> json(AccountView.render("show.json", %{user: updated_user}))
end
def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
@@ -70,7 +70,7 @@ def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
do:
conn
|> json(
- UserView.render("index_for_admin.json", %{
+ AccountView.render("index.json", %{
users: users,
count: count,
page_size: @users_page_size
diff --git a/lib/pleroma/web/mastodon_api/views/admin/account_view.ex b/lib/pleroma/web/mastodon_api/views/admin/account_view.ex
new file mode 100644
index 000000000..74ca13564
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/admin/account_view.ex
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
+ use Pleroma.Web, :view
+
+ alias Pleroma.Web.MastodonAPI.Admin.AccountView
+
+ def render("index.json", %{users: users, count: count, page_size: page_size}) do
+ %{
+ users: render_many(users, AccountView, "show.json", as: :user),
+ count: count,
+ page_size: page_size
+ }
+ end
+
+ def render("show.json", %{user: user}) do
+ %{
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "deactivated" => user.info.deactivated
+ }
+ end
+end
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index e8514d3ba..df7384476 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -9,7 +9,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MediaProxy
- alias Pleroma.Web.TwitterAPI.UserView
def render("show.json", %{user: user = %User{}} = assigns) do
render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns)
@@ -27,22 +26,6 @@ def render("user.json", %{user: user = %User{}} = assigns) do
else: %{}
end
- def render("index_for_admin.json", %{users: users, count: count, page_size: page_size} = opts) do
- %{
- users: render_many(users, UserView, "show_for_admin.json", opts),
- count: count,
- page_size: page_size
- }
- end
-
- def render("show_for_admin.json", %{user: user}) do
- %{
- "id" => user.id,
- "nickname" => user.nickname,
- "deactivated" => user.info.deactivated
- }
- end
-
def render("short.json", %{
user: %User{
nickname: nickname,
From 70e82a3465ee10004d0ae347934524e779bd778a Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Thu, 28 Feb 2019 17:54:02 +0300
Subject: [PATCH 027/184] Add test for the second page
---
.../admin_api/admin_api_controller_test.exs | 54 ++++++++++++-------
1 file changed, 36 insertions(+), 18 deletions(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 1b0a2f5be..893387ef5 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -331,26 +331,44 @@ test "/api/pleroma/admin/password_reset" do
assert conn.status == 200
end
- test "GET /api/pleroma/admin/users" do
- admin = insert(:user, info: %{is_admin: true})
- user = insert(:user)
+ describe "GET /api/pleroma/admin/users" do
+ test "renders users array for the first page" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users?page=1")
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users?page=1")
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- ]
- }
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+ end
+
+ test "renders empty array for the second page" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users?page=2")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => []
+ }
+ end
end
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
From e10ca35b3de0ca1b32ab5fd57f559a1cec1e5c3e Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 14:53:54 +0000
Subject: [PATCH 028/184] mix: update dependencies for cowboy 2.0
---
mix.exs | 5 ++---
mix.lock | 10 +++++-----
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/mix.exs b/mix.exs
index 5392d94d1..0fe9c6ec3 100644
--- a/mix.exs
+++ b/mix.exs
@@ -55,9 +55,8 @@ defp elixirc_paths(_), do: ["lib"]
# Type `mix help deps` for examples and options.
defp deps do
[
- # Until Phoenix 1.4.1 is released
- {:phoenix, github: "phoenixframework/phoenix", branch: "v1.4"},
- {:plug_cowboy, "~> 1.0"},
+ {:phoenix, "~> 1.4.1"},
+ {:plug_cowboy, "~> 2.0"},
{:phoenix_pubsub, "~> 1.1"},
{:phoenix_ecto, "~> 3.3"},
{:postgrex, ">= 0.13.5"},
diff --git a/mix.lock b/mix.lock
index 918702444..50e742fbd 100644
--- a/mix.lock
+++ b/mix.lock
@@ -9,8 +9,8 @@
"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"},
"cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
- "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
- "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"},
+ "cowboy": {:hex, :cowboy, "2.6.1", "f2e06f757c337b3b311f9437e6e072b678fcd71545a7b2865bdaa154d078593f", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
+ "cowlib": {:hex, :cowlib, "2.7.0", "3ef16e77562f9855a2605900cedb15c1462d76fb1be6a32fc3ae91973ee543d2", [:rebar3], [], "hexpm"},
"credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
@@ -45,17 +45,17 @@
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [: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": {:git, "https://github.com/phoenixframework/phoenix.git", "ea22dc50b574178a300ecd19253443960407df93", [branch: "v1.4"]},
+ "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"},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
- "plug_cowboy": {:hex, :plug_cowboy, "1.0.0", "2e2a7d3409746d335f451218b8bb0858301c3de6d668c3052716c909936eb57a", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
+ "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
- "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "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"},
"syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]},
From bc53dff5b6c7814a1cfeca43fc2a843e1e306501 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 15:17:01 +0000
Subject: [PATCH 029/184] mastodon api: websocket: update code for cowboy 2.x
---
.../web/mastodon_api/websocket_handler.ex | 39 +++++++++----------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index ea75070c4..f19f26b9a 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
alias Pleroma.Repo
alias Pleroma.User
- @behaviour :cowboy_websocket_handler
+ @behaviour :cowboy_websocket
@streams [
"public",
@@ -23,40 +23,37 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
]
@anonymous_streams ["public", "public:local", "hashtag"]
- # Handled by periodic keepalive in Pleroma.Web.Streamer.
- @timeout :infinity
-
- def init(_type, _req, _opts) do
- {:upgrade, :protocol, :cowboy_websocket}
- end
-
- def websocket_init(_type, req, _opts) do
+ def init(req, _state) do
with {qs, req} <- :cowboy_req.qs(req),
params <- :cow_qs.parse_qs(qs),
access_token <- List.keyfind(params, "access_token", 0),
{_, stream} <- List.keyfind(params, "stream", 0),
{:ok, user} <- allow_request(stream, access_token),
topic when is_binary(topic) <- expand_topic(stream, params) do
- send(self(), :subscribe)
- {:ok, req, %{user: user, topic: topic}, @timeout}
+ {:cowboy_websocket, req, %{user: user, topic: topic}}
else
{:error, code} ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}")
{:ok, req} = :cowboy_req.reply(code, req)
- {:shutdown, req}
+ {:stop, req}
error ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(error)} - #{inspect(req)}")
- {:shutdown, req}
+ {:stop, req}
end
end
- # We never receive messages.
- def websocket_handle(_frame, req, state) do
- {:ok, req, state}
+ def websocket_init(state) do
+ send(self(), :subscribe)
+ {:ok, state}
end
- def websocket_info(:subscribe, req, state) do
+ # We never receive messages.
+ def websocket_handle(_frame, state) do
+ {:ok, state}
+ end
+
+ def websocket_info(:subscribe, state) do
Logger.debug(
"#{__MODULE__} accepted websocket connection for user #{
(state.user || %{id: "anonymous"}).id
@@ -64,14 +61,14 @@ def websocket_info(:subscribe, req, state) do
)
Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state))
- {:ok, req, state}
+ {:ok, state}
end
- def websocket_info({:text, message}, req, state) do
- {:reply, {:text, message}, req, state}
+ def websocket_info({:text, message}, state) do
+ {:reply, {:text, message}, state}
end
- def websocket_terminate(reason, _req, state) do
+ def terminate(reason, _req, state) do
Logger.debug(
"#{__MODULE__} terminating websocket connection for user #{
(state.user || %{id: "anonymous"}).id
From 9aec00d71101b848aab6b61ad6c5335284fb339b Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 15:43:38 +0000
Subject: [PATCH 030/184] config: update config for cowboy 2 endpoints
---
config/config.exs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 7e4ac1100..374b4d86b 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -93,10 +93,10 @@
dispatch: [
{:_,
[
- {"/api/v1/streaming", Elixir.Pleroma.Web.MastodonAPI.WebsocketHandler, []},
- {"/socket/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/socket/websocket", Phoenix.Endpoint.CowboyWebsocket,
{nil, {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
- {:_, Plug.Adapters.Cowboy.Handler, {Pleroma.Web.Endpoint, []}}
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
]}
]
],
From f1d37a5e2399d06c8a2178c98825e77e5b381460 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 16:02:48 +0000
Subject: [PATCH 031/184] mastodon websocket: use pattern match to get query
data, robustly handle errors
---
lib/pleroma/web/mastodon_api/websocket_handler.ex | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index f19f26b9a..edab961f0 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -23,9 +23,8 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
]
@anonymous_streams ["public", "public:local", "hashtag"]
- def init(req, _state) do
- with {qs, req} <- :cowboy_req.qs(req),
- params <- :cow_qs.parse_qs(qs),
+ def init(%{qs: qs} = req, _state) do
+ with params <- :cow_qs.parse_qs(qs),
access_token <- List.keyfind(params, "access_token", 0),
{_, stream} <- List.keyfind(params, "stream", 0),
{:ok, user} <- allow_request(stream, access_token),
@@ -39,6 +38,7 @@ def init(req, _state) do
error ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(error)} - #{inspect(req)}")
+ {:ok, req} = :cowboy_req.reply(400, req)
{:stop, req}
end
end
From 46f29b9da1cfdcc2ab14616f999f061fa0c87ddc Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Thu, 28 Feb 2019 19:04:47 +0300
Subject: [PATCH 032/184] Add search users endpoint
---
lib/pleroma/user.ex | 8 +++----
.../web/admin_api/admin_api_controller.ex | 13 ++++++++++
lib/pleroma/web/router.ex | 1 +
.../admin_api/admin_api_controller_test.exs | 24 ++++++++++++++++++-
4 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 80e4ae296..52df171c5 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -755,18 +755,18 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
Repo.all(query)
end
- def search(query, resolve \\ false, for_user \\ nil) do
+ def search(query, resolve \\ false, for_user \\ nil, limit \\ 20) do
# Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@")
if resolve, do: get_or_fetch(query)
- fts_results = do_search(fts_search_subquery(query), for_user)
+ fts_results = do_search(fts_search_subquery(query), for_user, %{limit: limit})
{:ok, trigram_results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
- do_search(trigram_search_subquery(query), for_user)
+ do_search(trigram_search_subquery(query), for_user, %{limit: limit})
end)
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
@@ -793,7 +793,7 @@ def count_all_except_one(user) do
Repo.aggregate(query, :count, :id)
end
- defp do_search(subquery, for_user, options \\ []) do
+ defp do_search(subquery, for_user, options) do
q =
from(
s in subquery(subquery),
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index d8e3d57e1..37159cd40 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -78,6 +78,19 @@ def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
)
end
+ def search_users(%{assigns: %{user: admin}} = conn, %{"query" => query}) do
+ users = User.search(query, true, admin, @users_page_size)
+
+ conn
+ |> json(
+ AccountView.render("index.json", %{
+ users: users,
+ count: length(users),
+ page_size: @users_page_size
+ })
+ )
+ end
+
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
when permission_group in ["moderator", "admin"] do
user = User.get_by_nickname(nickname)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 3b1fd46a5..6fcb46878 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -140,6 +140,7 @@ defmodule Pleroma.Web.Router do
pipe_through([:admin_api, :oauth_write])
get("/users", AdminAPIController, :list_users)
+ get("/users/search", AdminAPIController, :search_users)
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 893387ef5..14625af32 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -356,7 +356,7 @@ test "renders users array for the first page" do
test "renders empty array for the second page" do
admin = insert(:user, info: %{is_admin: true})
- user = insert(:user)
+ insert(:user)
conn =
build_conn()
@@ -387,4 +387,26 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
"nickname" => user.nickname
}
end
+
+ test "GET /api/pleroma/admin/users/search" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user, nickname: "bob")
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users/search?query=bo")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+ end
end
From 388a3f4ca2299faca366f6dc19485dc03c307aa5 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 16:23:24 +0000
Subject: [PATCH 033/184] mastodon websocket: bring back infinity timeout
---
lib/pleroma/web/mastodon_api/websocket_handler.ex | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index edab961f0..bb7ecad69 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -23,13 +23,16 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
]
@anonymous_streams ["public", "public:local", "hashtag"]
- def init(%{qs: qs} = req, _state) do
+ # Handled by periodic keepalive in Pleroma.Web.Streamer.
+ @timeout :infinity
+
+ def init(%{qs: qs} = req, state) do
with params <- :cow_qs.parse_qs(qs),
access_token <- List.keyfind(params, "access_token", 0),
{_, stream} <- List.keyfind(params, "stream", 0),
{:ok, user} <- allow_request(stream, access_token),
topic when is_binary(topic) <- expand_topic(stream, params) do
- {:cowboy_websocket, req, %{user: user, topic: topic}}
+ {:cowboy_websocket, req, %{user: user, topic: topic}, %{idle_timeout: @timeout}}
else
{:error, code} ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}")
From 28b40932335e1b31a240f51740ace415ab558f43 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 16:23:55 +0000
Subject: [PATCH 034/184] mastodon websocket: return errors using ok, not stop
---
lib/pleroma/web/mastodon_api/websocket_handler.ex | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index bb7ecad69..8efe2efd5 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -37,12 +37,12 @@ def init(%{qs: qs} = req, state) do
{:error, code} ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}")
{:ok, req} = :cowboy_req.reply(code, req)
- {:stop, req}
+ {:ok, req, state}
error ->
Logger.debug("#{__MODULE__} denied connection: #{inspect(error)} - #{inspect(req)}")
{:ok, req} = :cowboy_req.reply(400, req)
- {:stop, req}
+ {:ok, req, state}
end
end
From 6b2a1ad1c84b7ef350b0d0be76d6b2e03c633260 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Thu, 28 Feb 2019 16:58:00 +0000
Subject: [PATCH 035/184] config: fix chat endpoint path
---
config/config.exs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/config/config.exs b/config/config.exs
index 374b4d86b..a620e7451 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -94,8 +94,9 @@
{:_,
[
{"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
- {"/socket/websocket", Phoenix.Endpoint.CowboyWebsocket,
- {nil, {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
]}
]
From 1341ee650ecde656f385454264f43b21051e86f2 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 1 Mar 2019 09:37:29 +0300
Subject: [PATCH 036/184] [#675] Do not show DMs in mentions timeline
---
lib/pleroma/web/activity_pub/activity_pub.ex | 24 +++++++++++++++++++
.../web/twitter_api/twitter_api_controller.ex | 1 +
test/web/activity_pub/activity_pub_test.exs | 8 +++++++
.../twitter_api_controller_test.exs | 19 ++++++++++++++-
4 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index cc255cc9e..a61bfa4db 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -420,6 +420,30 @@ def fetch_public_activities(opts \\ %{}) do
@valid_visibilities ~w[direct unlisted public private]
+ defp restrict_visibility(query, %{visibility: visibility})
+ when is_list(visibility) do
+ if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
+ query =
+ from(
+ a in query,
+ where:
+ fragment(
+ "activity_visibility(?, ?, ?) = ANY (?)",
+ a.actor,
+ a.recipients,
+ a.data,
+ ^visibility
+ )
+ )
+
+ Ecto.Adapters.SQL.to_sql(:all, Repo, query)
+
+ query
+ else
+ Logger.error("Could not restrict visibility to #{visibility}")
+ end
+ end
+
defp restrict_visibility(query, %{visibility: visibility})
when visibility in @valid_visibilities do
query =
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 0d74c30c3..41e3acc60 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -167,6 +167,7 @@ def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
params
|> Map.put("type", ["Create", "Announce", "Follow", "Like"])
|> Map.put("blocking_user", user)
+ |> Map.put(:visibility, ~w[unlisted public private])
activities = ActivityPub.fetch_activities([user.ap_id], params)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 11262c523..17f48797b 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -55,6 +55,14 @@ test "it restricts by the appropriate visibility" do
ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
assert activities == [public_activity]
+
+ activities =
+ ActivityPub.fetch_activities([], %{
+ :visibility => ~w[private public],
+ "actor_id" => user.ap_id
+ })
+
+ assert activities == [public_activity, private_activity]
end
end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 05a832967..ed5683779 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -427,7 +427,10 @@ test "without valid credentials", %{conn: conn} do
test "with credentials", %{conn: conn, user: current_user} do
{:ok, activity} =
- ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
+ ActivityBuilder.insert(
+ %{"to" => [current_user.ap_id, "https://www.w3.org/ns/activitystreams#Public"]},
+ %{user: current_user}
+ )
conn =
conn
@@ -445,6 +448,20 @@ test "with credentials", %{conn: conn, user: current_user} do
mentioned: [current_user]
})
end
+
+ test "does not show DMs in mentions timeline", %{conn: conn, user: current_user} do
+ {:ok, _activity} =
+ ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/statuses/mentions.json")
+
+ response = json_response(conn, 200)
+
+ assert length(response) == 0
+ end
end
describe "GET /api/qvitter/statuses/notifications.json" do
From 85734c0d49712d53791237e93637b86b848f0f66 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Fri, 1 Mar 2019 13:25:32 +0300
Subject: [PATCH 037/184] Added migration for setting default tags in existing
users records
---
.../20190301101154_add_default_tags_to_user.exs | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 priv/repo/migrations/20190301101154_add_default_tags_to_user.exs
diff --git a/priv/repo/migrations/20190301101154_add_default_tags_to_user.exs b/priv/repo/migrations/20190301101154_add_default_tags_to_user.exs
new file mode 100644
index 000000000..faeb8f1c6
--- /dev/null
+++ b/priv/repo/migrations/20190301101154_add_default_tags_to_user.exs
@@ -0,0 +1,9 @@
+defmodule Pleroma.Repo.Migrations.AddDefaultTagsToUser do
+ use Ecto.Migration
+
+ def up do
+ execute "UPDATE users SET tags = array[]::varchar[] where tags IS NULL"
+ end
+
+ def down, do: :noop
+end
From 689b0730f8074b283da255d4520d05cc1072557e Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Fri, 1 Mar 2019 12:21:09 +0000
Subject: [PATCH 038/184] activitypub: fix date header format
HTTP date header specification says that days must always be two-digit.
Accordingly, change the format string used to ensure days are always
represented as two-digit (e.g. 01).
---
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 52404c7e5..16ae65867 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -828,7 +828,7 @@ def publish_one(%{inbox: inbox, json: json, actor: actor, id: id} = params) do
date =
NaiveDateTime.utc_now()
- |> Timex.format!("{WDshort}, {D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
+ |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
signature =
Pleroma.Web.HTTPSignatures.sign(actor, %{
From 9c6abec4d8b2487edeb124aa197a5dd6d771e345 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Fri, 1 Mar 2019 15:48:04 +0300
Subject: [PATCH 039/184] use commonapi.post instead of activitybulder
---
.../web/twitter_api/twitter_api_controller_test.exs | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index ed5683779..7125d85ab 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -427,10 +427,10 @@ test "without valid credentials", %{conn: conn} do
test "with credentials", %{conn: conn, user: current_user} do
{:ok, activity} =
- ActivityBuilder.insert(
- %{"to" => [current_user.ap_id, "https://www.w3.org/ns/activitystreams#Public"]},
- %{user: current_user}
- )
+ CommonAPI.post(current_user, %{
+ "status" => "why is tenshi eating a corndog so cute?",
+ "visibility" => "public"
+ })
conn =
conn
@@ -451,7 +451,10 @@ test "with credentials", %{conn: conn, user: current_user} do
test "does not show DMs in mentions timeline", %{conn: conn, user: current_user} do
{:ok, _activity} =
- ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
+ CommonAPI.post(current_user, %{
+ "status" => "Have you guys ever seen how cute tenshi eating a corndog is?",
+ "visibility" => "direct"
+ })
conn =
conn
From adac7455122d37058bff2e4a805066f2cd24fbf9 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 17:34:14 +0300
Subject: [PATCH 040/184] Add docs to /users/search
---
docs/Admin-API.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 508981d38..ed19bc875 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -20,6 +20,26 @@ Authentication is required and the user must be an admin.
]
```
+## `/api/pleroma/admin/users/search?query={query}`
+
+### Search users
+
+- Method `GET`
+- Params:
+ - `query`
+- Response:
+
+```JSON
+[
+ {
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
+ },
+ ...
+]
+```
+
## `/api/pleroma/admin/user`
### Remove a user
From 5b08b470f69738f4528455a58fefe3a8d4acae02 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 20:13:02 +0300
Subject: [PATCH 041/184] Add "local" params to users search
---
docs/Admin-API.md | 7 ++-
lib/pleroma/user.ex | 39 ++++++++----
.../web/admin_api/admin_api_controller.ex | 10 ++-
.../mastodon_api/mastodon_api_controller.ex | 6 +-
.../web/twitter_api/twitter_api_controller.ex | 2 +-
.../admin_api/admin_api_controller_test.exs | 62 +++++++++++++------
6 files changed, 87 insertions(+), 39 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index ed19bc875..4403620bf 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -20,13 +20,14 @@ Authentication is required and the user must be an admin.
]
```
-## `/api/pleroma/admin/users/search?query={query}`
+## `/api/pleroma/admin/users/search?query={query}&local={local}`
-### Search users
+### Search users by name or nickname
- Method `GET`
- Params:
- - `query`
+ - `query`: **string** search term
+ - `local`: **bool** whether to return only local users
- Response:
```JSON
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 52df171c5..af3ce705d 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -755,18 +755,25 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
Repo.all(query)
end
- def search(query, resolve \\ false, for_user \\ nil, limit \\ 20) do
+ def search(term, options \\ %{}) do
# Strip the beginning @ off if there is a query
- query = String.trim_leading(query, "@")
+ term = String.trim_leading(term, "@")
+ query = options[:query] || User
- if resolve, do: get_or_fetch(query)
+ if options[:resolve], do: get_or_fetch(term)
- fts_results = do_search(fts_search_subquery(query), for_user, %{limit: limit})
+ fts_results =
+ do_search(fts_search_subquery(term, query), options[:for_user], %{
+ limit: options[:limit]
+ })
{:ok, trigram_results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
- do_search(trigram_search_subquery(query), for_user, %{limit: limit})
+
+ do_search(trigram_search_subquery(term, query), options[:for_user], %{
+ limit: options[:limit]
+ })
end)
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
@@ -809,9 +816,9 @@ defp do_search(subquery, for_user, options) do
boost_search_results(results, for_user)
end
- defp fts_search_subquery(query) do
+ defp fts_search_subquery(term, query) do
processed_query =
- query
+ term
|> String.replace(~r/\W+/, " ")
|> String.trim()
|> String.split()
@@ -819,7 +826,7 @@ defp fts_search_subquery(query) do
|> Enum.join(" | ")
from(
- u in User,
+ u in query,
select_merge: %{
search_rank:
fragment(
@@ -849,19 +856,19 @@ defp fts_search_subquery(query) do
)
end
- defp trigram_search_subquery(query) do
+ defp trigram_search_subquery(term, query) do
from(
- u in User,
+ u in query,
select_merge: %{
search_rank:
fragment(
"similarity(?, trim(? || ' ' || coalesce(?, '')))",
- ^query,
+ ^term,
u.nickname,
u.name
)
},
- where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^query)
+ where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term)
)
end
@@ -1018,6 +1025,14 @@ def unblock_domain(user, domain) do
update_and_set_cache(cng)
end
+ def maybe_local_user_query(local) when local == true do
+ local_user_query()
+ end
+
+ def maybe_local_user_query(local) when local == false do
+ User
+ end
+
def local_user_query do
from(
u in User,
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 37159cd40..a8f9e5012 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -78,8 +78,14 @@ def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
)
end
- def search_users(%{assigns: %{user: admin}} = conn, %{"query" => query}) do
- users = User.search(query, true, admin, @users_page_size)
+ def search_users(%{assigns: %{user: admin}} = conn, %{"query" => term} = params) do
+ users =
+ User.search(term,
+ query: User.maybe_local_user_query(params["local"] == "true"),
+ resolve: true,
+ for_user: admin,
+ limit: @users_page_size
+ )
conn
|> json(
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 12987442a..056be49b0 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -894,7 +894,7 @@ def status_search(user, query) do
end
def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true", user)
+ accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
statuses = status_search(user, query)
@@ -919,7 +919,7 @@ def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
end
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true", user)
+ accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
statuses = status_search(user, query)
@@ -941,7 +941,7 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
end
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
- accounts = User.search(query, params["resolve"] == "true", user)
+ accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 0d74c30c3..19264a93f 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -702,7 +702,7 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => _query} = params) do
end
def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do
- users = User.search(query, true, user)
+ users = User.search(query, resolve: true, for_user: user)
conn
|> put_view(UserView)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 14625af32..460f2a6bd 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -388,25 +388,51 @@ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
}
end
- test "GET /api/pleroma/admin/users/search" do
- admin = insert(:user, info: %{is_admin: true})
- user = insert(:user, nickname: "bob")
+ describe "GET /api/pleroma/admin/users/search" do
+ test "regular search" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user, nickname: "bob")
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users/search?query=bo")
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users/search?query=bo")
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- ]
- }
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+ end
+
+ test "only local users" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user, nickname: "bob")
+
+ insert(:user, nickname: "bobb", local: false)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users/search?query=bo&local=true")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+ end
end
end
From f1a4c3163b18692a7a8bd9874a45e75a6535dd5a Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 20:23:03 +0300
Subject: [PATCH 042/184] Show current user in users list as well
---
lib/pleroma/user.ex | 3 +-
.../web/admin_api/admin_api_controller.ex | 2 +-
.../admin_api/admin_api_controller_test.exs | 45 ++++++++++---------
3 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index af3ce705d..37f8da892 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -779,10 +779,9 @@ def search(term, options \\ %{}) do
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
end
- def all_except_one(user, page, page_size) do
+ def all(page, page_size) do
from(
u in User,
- where: u.id != ^user.id,
limit: ^page_size,
offset: ^((page - 1) * page_size),
order_by: u.id
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index a8f9e5012..270097d35 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -65,7 +65,7 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
with {page, _} <- Integer.parse(page_string),
- users <- User.all_except_one(admin, page, @users_page_size),
+ users <- User.all(page, @users_page_size),
count <- User.count_all_except_one(admin),
do:
conn
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 460f2a6bd..0679f5dfe 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -345,6 +345,11 @@ test "renders users array for the first page" do
"count" => 1,
"page_size" => 50,
"users" => [
+ %{
+ "deactivated" => admin.info.deactivated,
+ "id" => admin.id,
+ "nickname" => admin.nickname
+ },
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
@@ -399,16 +404,16 @@ test "regular search" do
|> get("/api/pleroma/admin/users/search?query=bo")
assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- ]
- }
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
end
test "only local users" do
@@ -423,16 +428,16 @@ test "only local users" do
|> get("/api/pleroma/admin/users/search?query=bo&local=true")
assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- ]
- }
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
end
end
end
From f384a9a2563d2fb6161ebb824534fda08cf67c64 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 20:23:19 +0300
Subject: [PATCH 043/184] Format
---
test/web/admin_api/admin_api_controller_test.exs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 0679f5dfe..a3042fa05 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -345,11 +345,11 @@ test "renders users array for the first page" do
"count" => 1,
"page_size" => 50,
"users" => [
- %{
- "deactivated" => admin.info.deactivated,
- "id" => admin.id,
- "nickname" => admin.nickname
- },
+ %{
+ "deactivated" => admin.info.deactivated,
+ "id" => admin.id,
+ "nickname" => admin.nickname
+ },
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
From aaa9fed1ca196b55d8c05af838d6947959548bf0 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 20:58:47 +0300
Subject: [PATCH 044/184] Fix user_test
---
test/user_test.exs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/user_test.exs b/test/user_test.exs
index 0b1c39ecf..27137fc35 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -901,7 +901,7 @@ test "finds users, boosting ranks of friends and followers" do
{:ok, follower} = User.follow(follower, u1)
{:ok, u1} = User.follow(u1, friend)
- assert [friend.id, follower.id, u2.id] == Enum.map(User.search("doe", false, u1), & &1.id)
+ assert [friend.id, follower.id, u2.id] == Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id)
end
test "finds a user whose name is nil" do
@@ -923,7 +923,7 @@ test "does not yield false-positive matches" do
end
test "works with URIs" do
- results = User.search("http://mastodon.example.org/users/admin", true)
+ results = User.search("http://mastodon.example.org/users/admin", resolve: true)
result = results |> List.first()
user = User.get_by_ap_id("http://mastodon.example.org/users/admin")
From a25c1313aee2f5f3d2b858b9802698f29acf4043 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 21:07:05 +0300
Subject: [PATCH 045/184] Format
---
test/user_test.exs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/user_test.exs b/test/user_test.exs
index 27137fc35..4f9de4e31 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -901,7 +901,8 @@ test "finds users, boosting ranks of friends and followers" do
{:ok, follower} = User.follow(follower, u1)
{:ok, u1} = User.follow(u1, friend)
- assert [friend.id, follower.id, u2.id] == Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id)
+ assert [friend.id, follower.id, u2.id] ==
+ Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id)
end
test "finds a user whose name is nil" do
From f635b675b2cc0bc10b395cd71ae1720b0696d364 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Fri, 1 Mar 2019 21:17:20 +0300
Subject: [PATCH 046/184] Refactor a little bit
---
lib/pleroma/user.ex | 16 ++++------------
.../web/admin_api/admin_api_controller.ex | 8 ++++----
2 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 37f8da892..3c6fb4f9b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -763,17 +763,13 @@ def search(term, options \\ %{}) do
if options[:resolve], do: get_or_fetch(term)
fts_results =
- do_search(fts_search_subquery(term, query), options[:for_user], %{
- limit: options[:limit]
- })
+ do_search(fts_search_subquery(term, query), options[:for_user], limit: options[:limit])
{:ok, trigram_results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
- do_search(trigram_search_subquery(term, query), options[:for_user], %{
- limit: options[:limit]
- })
+ do_search(trigram_search_subquery(term, query), options[:for_user], limit: options[:limit])
end)
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
@@ -1024,12 +1020,8 @@ def unblock_domain(user, domain) do
update_and_set_cache(cng)
end
- def maybe_local_user_query(local) when local == true do
- local_user_query()
- end
-
- def maybe_local_user_query(local) when local == false do
- User
+ def maybe_local_user_query(local) do
+ if local, do: local_user_query(), else: User
end
def local_user_query do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 270097d35..33f9689cd 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -70,11 +70,11 @@ def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
do:
conn
|> json(
- AccountView.render("index.json", %{
+ AccountView.render("index.json",
users: users,
count: count,
page_size: @users_page_size
- })
+ )
)
end
@@ -89,11 +89,11 @@ def search_users(%{assigns: %{user: admin}} = conn, %{"query" => term} = params)
conn
|> json(
- AccountView.render("index.json", %{
+ AccountView.render("index.json",
users: users,
count: length(users),
page_size: @users_page_size
- })
+ )
)
end
From b6a001a34c09a35070049065367ccb7f0382a1e1 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 04:04:16 +0100
Subject: [PATCH 047/184] Web.OAuth.OAuthController: Fix scopes Enum.join for
OAuth response
---
lib/pleroma/web/oauth/oauth_controller.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 7c1a3adbd..4309cf58f 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -114,7 +114,7 @@ def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
refresh_token: token.refresh_token,
created_at: DateTime.to_unix(inserted_at),
expires_in: 60 * 10,
- scope: Enum.join(token.scopes)
+ scope: Enum.join(token.scopes, " ")
}
json(conn, response)
From bb9e40968a90b882ba85e71a2622756e40563207 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 04:10:43 +0100
Subject: [PATCH 048/184] Web.OAuth.OAuthControllerTest: Add test against token
formatting
---
test/web/oauth/oauth_controller_test.exs | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 53d83e6e8..ed94416ff 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -165,10 +165,10 @@ test "issues a token for `password` grant_type with valid credentials, with full
test "issues a token for request with HTTP basic auth client credentials" do
user = insert(:user)
- app = insert(:oauth_app, scopes: ["scope1", "scope2"])
+ app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
- {:ok, auth} = Authorization.create_authorization(app, user, ["scope2"])
- assert auth.scopes == ["scope2"]
+ {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
+ assert auth.scopes == ["scope1", "scope2"]
app_encoded =
(URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
@@ -183,11 +183,13 @@ test "issues a token for request with HTTP basic auth client credentials" do
"redirect_uri" => app.redirect_uris
})
- assert %{"access_token" => token} = json_response(conn, 200)
+ assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
+
+ assert scope == "scope1 scope2"
token = Repo.get_by(Token, token: token)
assert token
- assert token.scopes == ["scope2"]
+ assert token.scopes == ["scope1", "scope2"]
end
test "rejects token exchange with invalid client credentials" do
From 56d4e3901217251b5fb19d3e688f376f5a8627c1 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Mon, 11 Feb 2019 22:27:02 +0100
Subject: [PATCH 049/184] Pleroma.User: Add rel=me to URLs where it linkbacks
to the profile
---
lib/pleroma/user.ex | 9 +++++++-
lib/pleroma/web/rel_me.ex | 46 +++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
create mode 100644 lib/pleroma/web/rel_me.ex
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d58274508..b54613274 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -22,6 +22,7 @@ defmodule Pleroma.User do
alias Pleroma.Web.OAuth
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.RelMe
require Logger
@@ -1202,8 +1203,14 @@ def parse_bio(bio, user) do
{String.trim(name, ":"), url}
end)
+ # TODO: get profile URLs other than user.ap_id
+ profile_urls = user[:ap_id]
+
bio
- |> CommonUtils.format_input("text/plain", mentions_format: :full)
+ |> CommonUtils.format_input("text/plain", %{
+ mentions_format: :full,
+ rel: &RelMe.maybe_put_rel_me(&1, profile_urls)
+ })
|> elem(0)
|> Formatter.emojify(emoji)
end
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
new file mode 100644
index 000000000..b23c49977
--- /dev/null
+++ b/lib/pleroma/web/rel_me.ex
@@ -0,0 +1,46 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.RelMe do
+ @hackney_options [
+ pool: :media,
+ timeout: 2_000,
+ recv_timeout: 2_000,
+ max_body: 2_000_000
+ ]
+
+ def parse(nil), do: {:error, "No URL provided"}
+
+ if Mix.env() == :test do
+ def parse(url), do: parse_url(url)
+ else
+ def parse(url) do
+ Cachex.fetch!(:rel_me_cache, url, fn _ ->
+ {:commit, parse_url(url)}
+ end)
+ rescue
+ e -> {:error, "Cachex error: #{inspect(e)}"}
+ end
+ end
+
+ defp parse_url(url) do
+ {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
+
+ Floki.attribute(html, "link[rel=me]", "href") ++ Floki.attribute(html, "a[rel=me]", "href")
+ rescue
+ e -> {:error, "Parsing error: #{inspect(e)}"}
+ end
+
+ def maybe_put_rel_me("http" <> _ = target_page, urls) when not is_nil(urls) do
+ if Enum.any?(parse(target_page), fn x -> x in urls end) do
+ "rel=\"me\" "
+ else
+ ""
+ end
+ end
+
+ def maybe_put_rel_me(_, _) do
+ ""
+ end
+end
From 25e588496adab62be79da65e8dc23426b8813159 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:13:04 +0100
Subject: [PATCH 050/184] Pleroma.Web.RelMeTest: Add test against
Pleroma.Web.RelMe
---
test/fixtures/rel_me_anchor.html | 14 +++++++++
test/fixtures/rel_me_link.html | 14 +++++++++
test/fixtures/rel_me_null.html | 13 ++++++++
test/web/rel_me_test.exs | 54 ++++++++++++++++++++++++++++++++
4 files changed, 95 insertions(+)
create mode 100644 test/fixtures/rel_me_anchor.html
create mode 100644 test/fixtures/rel_me_link.html
create mode 100644 test/fixtures/rel_me_null.html
create mode 100644 test/web/rel_me_test.exs
diff --git a/test/fixtures/rel_me_anchor.html b/test/fixtures/rel_me_anchor.html
new file mode 100644
index 000000000..5abcce129
--- /dev/null
+++ b/test/fixtures/rel_me_anchor.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Blog
+
+
+
+ Lorem ipsum
+ Lorem ipsum dolor sit ameph, …
+ lain’s account
+
+
+
diff --git a/test/fixtures/rel_me_link.html b/test/fixtures/rel_me_link.html
new file mode 100644
index 000000000..b9ff18f6e
--- /dev/null
+++ b/test/fixtures/rel_me_link.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Blog
+
+
+
+
+ Lorem ipsum
+ Lorem ipsum dolor sit ameph, …
+
+
+
diff --git a/test/fixtures/rel_me_null.html b/test/fixtures/rel_me_null.html
new file mode 100644
index 000000000..57d424b80
--- /dev/null
+++ b/test/fixtures/rel_me_null.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Blog
+
+
+
+ Lorem ipsum
+ Lorem ipsum dolor sit ameph, …
+
+
+
diff --git a/test/web/rel_me_test.exs b/test/web/rel_me_test.exs
new file mode 100644
index 000000000..94cc01728
--- /dev/null
+++ b/test/web/rel_me_test.exs
@@ -0,0 +1,54 @@
+defmodule Pleroma.Web.RelMeTest do
+ use ExUnit.Case, async: true
+
+ setup do
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: "http://example.com/rel_me/anchor"
+ } ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_anchor.html")}
+
+ %{
+ method: :get,
+ url: "http://example.com/rel_me/link"
+ } ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_link.html")}
+
+ %{
+ method: :get,
+ url: "http://example.com/rel_me/null"
+ } ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_null.html")}
+ end)
+
+ :ok
+ end
+
+ test "parse/1" do
+ hrefs = ["https://social.example.org/users/lain"]
+
+ assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/null") == {:ok, []}
+ assert {:error, _} = Pleroma.Web.RelMe.parse("http://example.com/rel_me/error")
+
+ assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/link") == {:ok, hrefs}
+ assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/anchor") == {:ok, hrefs}
+ end
+
+ test "maybe_put_rel_me/2" do
+ profile_urls = ["https://social.example.org/users/lain"]
+ attr = "rel=\"me\" "
+
+ assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/null", profile_urls) ==
+ ""
+
+ assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/error", profile_urls) ==
+ ""
+
+ assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/anchor", profile_urls) ==
+ attr
+
+ assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/link", profile_urls) ==
+ attr
+ end
+end
From 9b83236fb0292ae19a981b8f464183f8c6214a48 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:32:03 +0100
Subject: [PATCH 051/184] Pleroma.Web.RelMe: fixups
---
lib/pleroma/web/rel_me.ex | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index b23c49977..3f0ee9ac6 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -10,12 +10,10 @@ defmodule Pleroma.Web.RelMe do
max_body: 2_000_000
]
- def parse(nil), do: {:error, "No URL provided"}
-
if Mix.env() == :test do
- def parse(url), do: parse_url(url)
+ def parse(url) when is_binary(url), do: parse_url(url)
else
- def parse(url) do
+ def parse(url) when is_binary(url) do
Cachex.fetch!(:rel_me_cache, url, fn _ ->
{:commit, parse_url(url)}
end)
@@ -24,20 +22,27 @@ def parse(url) do
end
end
+ def parse(_), do: {:error, "No URL provided"}
+
defp parse_url(url) do
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
- Floki.attribute(html, "link[rel=me]", "href") ++ Floki.attribute(html, "a[rel=me]", "href")
+ data =
+ Floki.attribute(html, "link[rel=me]", "href") ++ Floki.attribute(html, "a[rel=me]", "href")
+
+ {:ok, data}
rescue
e -> {:error, "Parsing error: #{inspect(e)}"}
end
- def maybe_put_rel_me("http" <> _ = target_page, urls) when not is_nil(urls) do
- if Enum.any?(parse(target_page), fn x -> x in urls end) do
- "rel=\"me\" "
- else
- ""
- end
+ def maybe_put_rel_me("http" <> _ = target_page, profile_urls) when is_list(profile_urls) do
+ {:ok, rel_me_hrefs} = parse(target_page)
+
+ true = Enum.any?(rel_me_hrefs, fn x -> x in profile_urls end)
+
+ "rel=\"me\" "
+ rescue
+ _ -> ""
end
def maybe_put_rel_me(_, _) do
From 3d22642352b797c6963dba7c9116c27699d5c641 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:33:15 +0100
Subject: [PATCH 052/184] Pleroma.User: Pass an array to profile_urls
---
lib/pleroma/user.ex | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index b54613274..447beb25b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1204,7 +1204,7 @@ def parse_bio(bio, user) do
end)
# TODO: get profile URLs other than user.ap_id
- profile_urls = user[:ap_id]
+ profile_urls = [user[:ap_id]]
bio
|> CommonUtils.format_input("text/plain", %{
From 39a5bea9b73daa63203b0640d0a7906d6f1af143 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:57:28 +0100
Subject: [PATCH 053/184] Pleroma.User: Fix syntax and user.ap_id call
---
lib/pleroma/user.ex | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 447beb25b..a9592df6d 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1204,13 +1204,13 @@ def parse_bio(bio, user) do
end)
# TODO: get profile URLs other than user.ap_id
- profile_urls = [user[:ap_id]]
+ profile_urls = [user.ap_id]
bio
- |> CommonUtils.format_input("text/plain", %{
+ |> CommonUtils.format_input("text/plain", [
mentions_format: :full,
rel: &RelMe.maybe_put_rel_me(&1, profile_urls)
- })
+ ])
|> elem(0)
|> Formatter.emojify(emoji)
end
From 8e6f7fdb86bc7f90618c59ee4b13b30b94fda475 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:58:42 +0100
Subject: [PATCH 054/184] RelMe.maybe_put_rel_me/2: When true put "me"
otherwise nil
---
lib/pleroma/web/rel_me.ex | 6 +++---
test/web/rel_me_test.exs | 7 ++++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index 3f0ee9ac6..a07db966f 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -40,12 +40,12 @@ def maybe_put_rel_me("http" <> _ = target_page, profile_urls) when is_list(profi
true = Enum.any?(rel_me_hrefs, fn x -> x in profile_urls end)
- "rel=\"me\" "
+ "me"
rescue
- _ -> ""
+ _ -> nil
end
def maybe_put_rel_me(_, _) do
- ""
+ nil
end
end
diff --git a/test/web/rel_me_test.exs b/test/web/rel_me_test.exs
index 94cc01728..ba8038e69 100644
--- a/test/web/rel_me_test.exs
+++ b/test/web/rel_me_test.exs
@@ -37,13 +37,14 @@ test "parse/1" do
test "maybe_put_rel_me/2" do
profile_urls = ["https://social.example.org/users/lain"]
- attr = "rel=\"me\" "
+ attr = "me"
+ fallback = nil
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/null", profile_urls) ==
- ""
+ fallback
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/error", profile_urls) ==
- ""
+ fallback
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/anchor", profile_urls) ==
attr
From 7b9868f34344144bfb965cdd099f71b2617976c6 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 06:59:09 +0100
Subject: [PATCH 055/184] Pleroma.UserTest: Add tests for rel=me
---
test/user_test.exs | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/test/user_test.exs b/test/user_test.exs
index cbe4693fc..e182a809f 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1039,6 +1039,22 @@ test "preserves hosts in user links text" do
assert expected_text == User.parse_bio(bio, user)
end
+
+ test "Adds rel=me on linkbacked urls" do
+ user = insert(:user, ap_id: "http://social.example.org/users/lain")
+
+ bio = "http://example.org/rel_me/null"
+ expected_text = "#{bio} "
+ assert expected_text == User.parse_bio(bio, user)
+
+ bio = "http://example.org/rel_me/link"
+ expected_text = "#{bio} "
+ assert expected_text == User.parse_bio(bio, user)
+
+ bio = "http://example.org/rel_me/anchor"
+ expected_text = "#{bio} "
+ assert expected_text == User.parse_bio(bio, user)
+ end
end
test "bookmarks" do
From f2452d5700afc48284638ae2cd1bff4886571d8c Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Sat, 2 Mar 2019 07:04:49 +0100
Subject: [PATCH 056/184] Pleroma.User: mix format
---
lib/pleroma/user.ex | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index a9592df6d..6ec1033a5 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1207,10 +1207,10 @@ def parse_bio(bio, user) do
profile_urls = [user.ap_id]
bio
- |> CommonUtils.format_input("text/plain", [
+ |> CommonUtils.format_input("text/plain",
mentions_format: :full,
rel: &RelMe.maybe_put_rel_me(&1, profile_urls)
- ])
+ )
|> elem(0)
|> Formatter.emojify(emoji)
end
From 2ec8cf566569912b767e15ab467cadd04fd1fd1c Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Sat, 2 Mar 2019 17:21:18 +0300
Subject: [PATCH 057/184] Add pagination to search
---
lib/pleroma/user.ex | 110 ++++++++++--------
.../web/admin_api/admin_api_controller.ex | 66 +++++++----
.../admin_api/admin_api_controller_test.exs | 46 +++++++-
3 files changed, 152 insertions(+), 70 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 3c6fb4f9b..230155c33 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -547,11 +547,8 @@ def get_followers_query(%User{id: id, follower_address: follower_address}, nil)
end
def get_followers_query(user, page) do
- from(
- u in get_followers_query(user, nil),
- limit: 20,
- offset: ^((page - 1) * 20)
- )
+ from(u in get_followers_query(user, nil))
+ |> paginate(page, 20)
end
def get_followers_query(user), do: get_followers_query(user, nil)
@@ -577,11 +574,8 @@ def get_friends_query(%User{id: id, following: following}, nil) do
end
def get_friends_query(user, page) do
- from(
- u in get_friends_query(user, nil),
- limit: 20,
- offset: ^((page - 1) * 20)
- )
+ from(u in get_friends_query(user, nil))
+ |> paginate(page, 20)
end
def get_friends_query(user), do: get_friends_query(user, nil)
@@ -755,47 +749,64 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
Repo.all(query)
end
- def search(term, options \\ %{}) do
- # Strip the beginning @ off if there is a query
+ @spec search_for_admin(binary(), %{
+ admin: Pleroma.User.t(),
+ local: boolean(),
+ page: number(),
+ page_size: number()
+ }) :: {:ok, [Pleroma.User.t()], number()}
+ def search_for_admin(term, %{admin: admin, local: local, page: page, page_size: page_size}) do
term = String.trim_leading(term, "@")
- query = options[:query] || User
- if options[:resolve], do: get_or_fetch(term)
+ local_paginated_query =
+ User
+ |> maybe_local_user_query(local)
+ |> paginate(page, page_size)
- fts_results =
- do_search(fts_search_subquery(term, query), options[:for_user], limit: options[:limit])
+ search_query = fts_search_subquery(term, local_paginated_query)
+
+ count =
+ term
+ |> fts_search_subquery()
+ |> maybe_local_user_query(local)
+ |> Repo.aggregate(:count, :id)
+
+ {:ok, do_search(search_query, admin), count}
+ end
+
+ @spec all_for_admin(number(), number()) :: {:ok, [Pleroma.User.t()], number()}
+ def all_for_admin(page, page_size) do
+ query = from(u in User, order_by: u.id)
+
+ paginated_query =
+ query
+ |> paginate(page, page_size)
+
+ count =
+ query
+ |> Repo.aggregate(:count, :id)
+
+ {:ok, Repo.all(paginated_query), count}
+ end
+
+ def search(query, resolve \\ false, for_user \\ nil) do
+ # Strip the beginning @ off if there is a query
+ query = String.trim_leading(query, "@")
+
+ if resolve, do: get_or_fetch(query)
+
+ fts_results = do_search(fts_search_subquery(query), for_user)
{:ok, trigram_results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
-
- do_search(trigram_search_subquery(term, query), options[:for_user], limit: options[:limit])
+ do_search(trigram_search_subquery(query), for_user)
end)
Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
end
- def all(page, page_size) do
- from(
- u in User,
- limit: ^page_size,
- offset: ^((page - 1) * page_size),
- order_by: u.id
- )
- |> Repo.all()
- end
-
- def count_all_except_one(user) do
- query =
- from(
- u in User,
- where: u.id != ^user.id
- )
-
- Repo.aggregate(query, :count, :id)
- end
-
- defp do_search(subquery, for_user, options) do
+ defp do_search(subquery, for_user, options \\ []) do
q =
from(
s in subquery(subquery),
@@ -811,7 +822,7 @@ defp do_search(subquery, for_user, options) do
boost_search_results(results, for_user)
end
- defp fts_search_subquery(term, query) do
+ defp fts_search_subquery(term, query \\ User) do
processed_query =
term
|> String.replace(~r/\W+/, " ")
@@ -851,9 +862,9 @@ defp fts_search_subquery(term, query) do
)
end
- defp trigram_search_subquery(term, query) do
+ defp trigram_search_subquery(term) do
from(
- u in query,
+ u in User,
select_merge: %{
search_rank:
fragment(
@@ -1020,13 +1031,13 @@ def unblock_domain(user, domain) do
update_and_set_cache(cng)
end
- def maybe_local_user_query(local) do
- if local, do: local_user_query(), else: User
+ def maybe_local_user_query(query, local) do
+ if local, do: local_user_query(query), else: query
end
- def local_user_query do
+ def local_user_query(query \\ User) do
from(
- u in User,
+ u in query,
where: u.local == true,
where: not is_nil(u.nickname)
)
@@ -1318,4 +1329,11 @@ def all_superusers do
)
|> Repo.all()
end
+
+ defp paginate(query, page, page_size) do
+ from(u in query,
+ limit: ^page_size,
+ offset: ^((page - 1) * page_size)
+ )
+ end
end
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 33f9689cd..aae02cab8 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -63,38 +63,40 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
do: json_response(conn, :no_content, "")
end
- def list_users(%{assigns: %{user: admin}} = conn, %{"page" => page_string}) do
- with {page, _} <- Integer.parse(page_string),
- users <- User.all(page, @users_page_size),
- count <- User.count_all_except_one(admin),
+ def list_users(conn, params) do
+ {page, page_size} = page_params(params)
+
+ with {:ok, users, count} <- User.all_for_admin(page, page_size),
do:
conn
|> json(
AccountView.render("index.json",
users: users,
count: count,
- page_size: @users_page_size
+ page_size: page_size
)
)
end
- def search_users(%{assigns: %{user: admin}} = conn, %{"query" => term} = params) do
- users =
- User.search(term,
- query: User.maybe_local_user_query(params["local"] == "true"),
- resolve: true,
- for_user: admin,
- limit: @users_page_size
- )
+ def search_users(%{assigns: %{user: admin}} = conn, %{"query" => query} = params) do
+ {page, page_size} = page_params(params)
- conn
- |> json(
- AccountView.render("index.json",
- users: users,
- count: length(users),
- page_size: @users_page_size
- )
- )
+ with {:ok, users, count} <-
+ User.search_for_admin(query, %{
+ admin: admin,
+ local: params["local"] == "true",
+ page: page,
+ page_size: page_size
+ }),
+ do:
+ conn
+ |> json(
+ AccountView.render("index.json",
+ users: users,
+ count: count,
+ page_size: page_size
+ )
+ )
end
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
@@ -240,4 +242,26 @@ def errors(conn, _) do
|> put_status(500)
|> json("Something went wrong")
end
+
+ defp page_params(params) do
+ {get_page(params["page"]), get_page_size(params["page_size"])}
+ end
+
+ defp get_page(page_string) when is_nil(page_string), do: 1
+
+ defp get_page(page_string) do
+ case Integer.parse(page_string) do
+ {page, _} -> page
+ :error -> 1
+ end
+ end
+
+ defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
+
+ defp get_page_size(page_size_string) do
+ case Integer.parse(page_size_string) do
+ {page_size, _} -> page_size
+ :error -> @users_page_size
+ end
+ end
end
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index a3042fa05..42e0daf8e 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -342,7 +342,7 @@ test "renders users array for the first page" do
|> get("/api/pleroma/admin/users?page=1")
assert json_response(conn, 200) == %{
- "count" => 1,
+ "count" => 2,
"page_size" => 50,
"users" => [
%{
@@ -369,7 +369,7 @@ test "renders empty array for the second page" do
|> get("/api/pleroma/admin/users?page=2")
assert json_response(conn, 200) == %{
- "count" => 1,
+ "count" => 2,
"page_size" => 50,
"users" => []
}
@@ -416,9 +416,49 @@ test "regular search" do
}
end
- test "only local users" do
+ test "regular search with page size" do
admin = insert(:user, info: %{is_admin: true})
user = insert(:user, nickname: "bob")
+ user2 = insert(:user, nickname: "bo")
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users/search?query=bo&page_size=1&page=1")
+
+ assert json_response(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 1,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users/search?query=bo&page_size=1&page=2")
+
+ assert json_response(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 1,
+ "users" => [
+ %{
+ "deactivated" => user2.info.deactivated,
+ "id" => user2.id,
+ "nickname" => user2.nickname
+ }
+ ]
+ }
+ end
+
+ test "only local users" do
+ admin = insert(:user, info: %{is_admin: true}, nickname: "john")
+ user = insert(:user, nickname: "bob")
insert(:user, nickname: "bobb", local: false)
From bf30df99cb9a08870f7c6a25e0f9f3d2e03d5de7 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Sat, 2 Mar 2019 17:32:40 +0300
Subject: [PATCH 058/184] We do not guarantee the order of elements when we
search
---
test/user_test.exs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/user_test.exs b/test/user_test.exs
index 4f9de4e31..188ab1a5c 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -901,8 +901,8 @@ test "finds users, boosting ranks of friends and followers" do
{:ok, follower} = User.follow(follower, u1)
{:ok, u1} = User.follow(u1, friend)
- assert [friend.id, follower.id, u2.id] ==
- Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id)
+ assert [friend.id, follower.id, u2.id] --
+ Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == []
end
test "finds a user whose name is nil" do
From 08c6aeeed7ff5db242050d06e707f99b6d75684d Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Sat, 2 Mar 2019 17:32:46 +0300
Subject: [PATCH 059/184] Add docs
---
docs/Admin-API.md | 49 ++++++++++++++++++++++++++++++-----------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 4403620bf..407647645 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -7,20 +7,27 @@ Authentication is required and the user must be an admin.
### List users
- Method `GET`
+- Params:
+ - `page`: **integer** page number
+ - `page_size`: **integer** number of users per page (default is `50`)
- Response:
```JSON
-[
+{
+ "page_size": integer,
+ "count": integer,
+ "users": [
{
- "deactivated": bool,
- "id": integer,
- "nickname": string
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
},
...
-]
+ ]
+}
```
-## `/api/pleroma/admin/users/search?query={query}&local={local}`
+## `/api/pleroma/admin/users/search?query={query}&local={local}&page={page}&page_size={page_size}`
### Search users by name or nickname
@@ -28,17 +35,23 @@ Authentication is required and the user must be an admin.
- Params:
- `query`: **string** search term
- `local`: **bool** whether to return only local users
+ - `page`: **integer** page number
+ - `page_size`: **integer** number of users per page (default is `50`)
- Response:
```JSON
-[
+{
+ "page_size": integer,
+ "count": integer,
+ "users": [
{
- "deactivated": bool,
- "id": integer,
- "nickname": string
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
},
...
-]
+ ]
+}
```
## `/api/pleroma/admin/user`
@@ -70,9 +83,9 @@ Authentication is required and the user must be an admin.
```JSON
{
- "deactivated": bool,
- "id": integer,
- "nickname": string
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
}
```
@@ -102,8 +115,8 @@ Authentication is required and the user must be an admin.
```JSON
{
- "is_moderator": bool,
- "is_admin": bool
+ "is_moderator": bool,
+ "is_admin": bool
}
```
@@ -119,8 +132,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
```JSON
{
- "is_moderator": bool,
- "is_admin": bool
+ "is_moderator": bool,
+ "is_admin": bool
}
```
From 1a1f4520cd711d46a53ffa0ec657f8a7e46896e7 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sat, 2 Mar 2019 22:18:51 +0300
Subject: [PATCH 060/184] Use sql query in User.get_follow_requests/1 for
filtering logic
---
lib/pleroma/user.ex | 15 +++++++--------
test/user_test.exs | 14 ++++++++++++++
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d58274508..06b430ccd 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -648,15 +648,14 @@ def update_follow_request_count(%User{} = user) do
end
def get_follow_requests(%User{} = user) do
- q = get_follow_requests_query(user)
- reqs = Repo.all(q)
-
users =
- Enum.map(reqs, fn req -> req.actor end)
- |> Enum.uniq()
- |> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
- |> Enum.filter(fn u -> !is_nil(u) end)
- |> Enum.filter(fn u -> !following?(u, user) end)
+ user
+ |> User.get_follow_requests_query()
+ |> join(:inner, [a], u in User, a.actor == u.ap_id)
+ |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
+ |> group_by([a, u], u.id)
+ |> select([a, u], u)
+ |> Repo.all()
{:ok, users}
end
diff --git a/test/user_test.exs b/test/user_test.exs
index cbe4693fc..b8d41ecfd 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -64,6 +64,20 @@ test "returns all pending follow requests" do
assert activity
end
+ test "doesn't return already accepted or duplicate follow requests" do
+ locked = insert(:user, %{info: %{locked: true}})
+ pending_follower = insert(:user)
+ accepted_follower = insert(:user)
+
+ Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
+ Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
+ Pleroma.Web.TwitterAPI.TwitterAPI.follow(accepted_follower, %{"user_id" => locked.id})
+ User.maybe_follow(accepted_follower, locked)
+
+ assert {:ok, [activity]} = User.get_follow_requests(locked)
+ assert activity
+ end
+
test "follow_all follows mutliple users" do
user = insert(:user)
followed_zero = insert(:user)
From c46950d3b16e6fe1ebb86a202ca47a810bfb76dc Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sun, 3 Mar 2019 13:21:03 +0300
Subject: [PATCH 061/184] Increment user note count only on public activities
---
lib/pleroma/web/activity_pub/activity_pub.ex | 12 +++++-
test/web/activity_pub/activity_pub_test.exs | 43 ++++++++++++++++++++
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 16ae65867..4e2056e20 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -81,6 +81,14 @@ defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(
defp check_remote_limit(_), do: true
+ def increase_note_count_if_public(actor, object) do
+ if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
+ end
+
+ def decrease_note_count_if_public(actor, object) do
+ if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
+ end
+
def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map),
@@ -163,7 +171,7 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d
),
{:ok, activity} <- insert(create_data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
- {:ok, _actor} <- User.increase_note_count(actor),
+ {:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
@@ -316,7 +324,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru
with {:ok, _} <- Object.delete(object),
{:ok, activity} <- insert(data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
- {:ok, _actor} <- User.decrease_note_count(user),
+ {:ok, _actor} <- decrease_note_count_if_public(user, object),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index ac3a565de..70a98824d 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -205,6 +205,25 @@ test "removes doubled 'to' recipients" do
assert activity.actor == user.ap_id
assert activity.recipients == ["user1", "user2", user.ap_id]
end
+
+ test "increases user note count only for public activities" do
+ user = insert(:user)
+
+ {:ok, _} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"})
+
+ {:ok, _} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"})
+
+ {:ok, _} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"})
+
+ {:ok, _} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"})
+
+ user = Repo.get(User, user.id)
+ assert user.info.note_count == 2
+ end
end
describe "fetch activities for recipients" do
@@ -640,6 +659,30 @@ test "it creates a delete activity and deletes the original object" do
assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end
+
+ test "decrements user note count only for public activities" do
+ user = insert(:user, info: %{note_count: 10})
+
+ {:ok, a1} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"})
+
+ {:ok, a2} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"})
+
+ {:ok, a3} =
+ CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"})
+
+ {:ok, a4} =
+ CommonAPI.post(Repo.get(User, 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)
+ assert user.info.note_count == 10
+ end
end
describe "timeline post-processing" do
From 8a1e0c9bee4173a7cd2c6b6174293097d78bea19 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sun, 3 Mar 2019 15:35:32 +0300
Subject: [PATCH 062/184] Added migration to update existing user note counters
---
...190303120636_update_user_note_counters.exs | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 priv/repo/migrations/20190303120636_update_user_note_counters.exs
diff --git a/priv/repo/migrations/20190303120636_update_user_note_counters.exs b/priv/repo/migrations/20190303120636_update_user_note_counters.exs
new file mode 100644
index 000000000..54e68f7c9
--- /dev/null
+++ b/priv/repo/migrations/20190303120636_update_user_note_counters.exs
@@ -0,0 +1,41 @@
+defmodule Pleroma.Repo.Migrations.UpdateUserNoteCounters do
+ use Ecto.Migration
+
+ @public "https://www.w3.org/ns/activitystreams#Public"
+
+ def up do
+ execute """
+ WITH public_note_count AS (
+ SELECT
+ data->>'actor' AS actor,
+ count(id) AS count
+ FROM objects
+ WHERE data->>'type' = 'Note' AND (
+ data->'cc' ? '#{@public}' OR data->'to' ? '#{@public}'
+ )
+ GROUP BY data->>'actor'
+ )
+ UPDATE users AS u
+ SET "info" = jsonb_set(u.info, '{note_count}', o.count::varchar::jsonb, true)
+ FROM public_note_count AS o
+ WHERE u.ap_id = o.actor
+ """
+ end
+
+ def down do
+ execute """
+ WITH public_note_count AS (
+ SELECT
+ data->>'actor' AS actor,
+ count(id) AS count
+ FROM objects
+ WHERE data->>'type' = 'Note'
+ GROUP BY data->>'actor'
+ )
+ UPDATE users AS u
+ SET "info" = jsonb_set(u.info, '{note_count}', o.count::varchar::jsonb, true)
+ FROM public_note_count AS o
+ WHERE u.ap_id = o.actor
+ """
+ end
+end
From af0039a3a0b7f466120211f2c81361311ecbcf02 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sun, 3 Mar 2019 17:27:09 +0300
Subject: [PATCH 063/184] Use atomic update for note count and follower count
---
lib/pleroma/user.ex | 87 +++++++++++++++++++++++++++++----------------
1 file changed, 56 insertions(+), 31 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d58274508..115c03176 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -662,23 +662,43 @@ def get_follow_requests(%User{} = user) do
end
def increase_note_count(%User{} = user) do
- info_cng = User.Info.add_to_note_count(user.info, 1)
-
- cng =
- change(user)
- |> put_embed(:info, info_cng)
-
- update_and_set_cache(cng)
+ User
+ |> where(id: ^user.id)
+ |> update([u],
+ set: [
+ info:
+ fragment(
+ "jsonb_set(?, '{note_count}', ((?->>'note_count')::int + 1)::varchar::jsonb, true)",
+ u.info,
+ u.info
+ )
+ ]
+ )
+ |> Repo.update_all([], returning: true)
+ |> case do
+ {1, [user]} -> set_cache(user)
+ _ -> {:error, user}
+ end
end
def decrease_note_count(%User{} = user) do
- info_cng = User.Info.add_to_note_count(user.info, -1)
-
- cng =
- change(user)
- |> put_embed(:info, info_cng)
-
- update_and_set_cache(cng)
+ User
+ |> where(id: ^user.id)
+ |> update([u],
+ set: [
+ info:
+ fragment(
+ "jsonb_set(?, '{note_count}', (greatest(0, (?->>'note_count')::int - 1))::varchar::jsonb, true)",
+ u.info,
+ u.info
+ )
+ ]
+ )
+ |> Repo.update_all([], returning: true)
+ |> case do
+ {1, [user]} -> set_cache(user)
+ _ -> {:error, user}
+ end
end
def update_note_count(%User{} = user) do
@@ -702,24 +722,29 @@ def update_note_count(%User{} = user) do
def update_follower_count(%User{} = user) do
follower_count_query =
- from(
- u in User,
- where: ^user.follower_address in u.following,
- where: u.id != ^user.id,
- select: count(u.id)
- )
+ User
+ |> where([u], ^user.follower_address in u.following)
+ |> where([u], u.id != ^user.id)
+ |> select([u], %{count: count(u.id)})
- follower_count = Repo.one(follower_count_query)
-
- info_cng =
- user.info
- |> User.Info.set_follower_count(follower_count)
-
- cng =
- change(user)
- |> put_embed(:info, info_cng)
-
- update_and_set_cache(cng)
+ User
+ |> where(id: ^user.id)
+ |> join(:inner, [u], s in subquery(follower_count_query))
+ |> update([u, s],
+ set: [
+ info:
+ fragment(
+ "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)",
+ u.info,
+ s.count
+ )
+ ]
+ )
+ |> Repo.update_all([], returning: true)
+ |> case do
+ {1, [user]} -> set_cache(user)
+ _ -> {:error, user}
+ end
end
def get_users_from_set_query(ap_ids, false) do
From d5418e9ff78785c48bc94fbc8cb146ffe90c1fc5 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Sun, 3 Mar 2019 18:39:37 +0300
Subject: [PATCH 064/184] Remove follow_request_count as it's not needed for FE
anymore.
MastoFE uses `GET /api/v1/follow_requests` and PleromaFE uses
`GET /api/pleroma/friend_requests` which they query on the initial page
load.
---
lib/pleroma/user.ex | 26 -------------------
lib/pleroma/user/info.ex | 1 -
lib/pleroma/web/activity_pub/activity_pub.ex | 12 +++------
.../web/twitter_api/views/user_view.ex | 9 -------
.../mastodon_api_controller_test.exs | 4 ---
.../twitter_api_controller_test.exs | 5 ----
6 files changed, 4 insertions(+), 53 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index d58274508..0d2b838db 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -621,32 +621,6 @@ def get_follow_requests_query(%User{} = user) do
)
end
- def update_follow_request_count(%User{} = user) do
- subquery =
- user
- |> User.get_follow_requests_query()
- |> select([a], %{count: count(a.id)})
-
- User
- |> where(id: ^user.id)
- |> join(:inner, [u], s in subquery(subquery))
- |> update([u, s],
- set: [
- info:
- fragment(
- "jsonb_set(?, '{follow_request_count}', ?::varchar::jsonb, true)",
- u.info,
- s.count
- )
- ]
- )
- |> Repo.update_all([], returning: true)
- |> case do
- {1, [user]} -> {:ok, user}
- _ -> {:error, user}
- end
- end
-
def get_follow_requests(%User{} = user) do
q = get_follow_requests_query(user)
reqs = Repo.all(q)
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 00a0f6df3..818b64645 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -12,7 +12,6 @@ defmodule Pleroma.User.Info do
field(:source_data, :map, default: %{})
field(:note_count, :integer, default: 0)
field(:follower_count, :integer, default: 0)
- field(:follow_request_count, :integer, default: 0)
field(:locked, :boolean, default: false)
field(:confirmation_pending, :boolean, default: false)
field(:confirmation_token, :string, default: nil)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index b81198629..7282d4239 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -175,8 +175,7 @@ def accept(%{to: to, actor: actor, object: object} = params) do
with data <- %{"to" => to, "type" => "Accept", "actor" => actor.ap_id, "object" => object},
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- _ <- User.update_follow_request_count(actor) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@@ -187,8 +186,7 @@ def reject(%{to: to, actor: actor, object: object} = params) do
with data <- %{"to" => to, "type" => "Reject", "actor" => actor.ap_id, "object" => object},
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- _ <- User.update_follow_request_count(actor) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@@ -286,8 +284,7 @@ def unannounce(
def follow(follower, followed, activity_id \\ nil, local \\ true) do
with data <- make_follow_data(follower, followed, activity_id),
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- _ <- User.update_follow_request_count(followed) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
@@ -297,8 +294,7 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
{:ok, activity} <- insert(unfollow_data, local),
- :ok <- maybe_federate(activity),
- _ <- User.update_follow_request_count(followed) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
end
end
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 22f33e0b5..e72ce977c 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -133,7 +133,6 @@ defp do_render("user.json", %{user: user = %User{}} = assigns) do
"tags" => user.tags
}
|> maybe_with_activation_status(user, for_user)
- |> maybe_with_follow_request_count(user, for_user)
}
data =
@@ -155,14 +154,6 @@ defp maybe_with_activation_status(data, user, %User{info: %{is_admin: true}}) do
defp maybe_with_activation_status(data, _, _), do: data
- defp maybe_with_follow_request_count(data, %User{id: id, info: %{locked: true}} = user, %User{
- id: id
- }) do
- Map.put(data, "follow_request_count", user.info.follow_request_count)
- end
-
- defp maybe_with_follow_request_count(data, _, _), do: data
-
defp maybe_with_role(data, %User{id: id} = user, %User{id: id}) do
Map.merge(data, %{"role" => role(user), "show_role" => user.info.show_role})
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index b52c2b805..f7f10662a 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -946,7 +946,6 @@ test "/api/v1/follow_requests/:id/authorize works" do
other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false
- assert user.info.follow_request_count == 1
conn =
build_conn()
@@ -960,7 +959,6 @@ test "/api/v1/follow_requests/:id/authorize works" do
other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == true
- assert user.info.follow_request_count == 0
end
test "verify_credentials", %{conn: conn} do
@@ -982,7 +980,6 @@ test "/api/v1/follow_requests/:id/reject works" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
user = Repo.get(User, user.id)
- assert user.info.follow_request_count == 1
conn =
build_conn()
@@ -996,7 +993,6 @@ test "/api/v1/follow_requests/:id/reject works" do
other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false
- assert user.info.follow_request_count == 0
end
end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 7125d85ab..d18b65876 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -690,7 +690,6 @@ test "for restricted account", %{conn: conn, user: current_user} do
followed = Repo.get(User, followed.id)
refute User.ap_followers(followed) in current_user.following
- assert followed.info.follow_request_count == 1
assert json_response(conn, 200) ==
UserView.render("show.json", %{user: followed, for: current_user})
@@ -1757,7 +1756,6 @@ test "it approves a friend request" do
other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false
- assert user.info.follow_request_count == 1
conn =
build_conn()
@@ -1769,7 +1767,6 @@ test "it approves a friend request" do
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == true
- assert user.info.follow_request_count == 0
end
end
@@ -1784,7 +1781,6 @@ test "it denies a friend request" do
other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false
- assert user.info.follow_request_count == 1
conn =
build_conn()
@@ -1796,7 +1792,6 @@ test "it denies a friend request" do
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == false
- assert user.info.follow_request_count == 0
end
end
From 9962121bff4009913d9af3f5cb851386d5948232 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Sun, 3 Mar 2019 20:32:46 +0300
Subject: [PATCH 065/184] Remove TODO.txt
---
TODO.txt | 12 ------------
1 file changed, 12 deletions(-)
delete mode 100644 TODO.txt
diff --git a/TODO.txt b/TODO.txt
deleted file mode 100644
index 3138d0848..000000000
--- a/TODO.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Unliking:
-
-- Add a proper undo activity, find out how to ignore those in twitter api.
-
-WEBSUB:
-
-- Add unsubscription
-
-OSTATUS:
-
-- Save and output 'updated'
-
From 88a672fe88deae53d5459d651859be65555e6af2 Mon Sep 17 00:00:00 2001
From: link0ff
Date: Sun, 3 Mar 2019 21:20:36 +0200
Subject: [PATCH 066/184] Move LDAP code to LDAPAuthenticator. Use
Authenticator for token_exchange with grant_type as well
---
docs/config.md | 5 +++
.../auth/ldap_authenticator.ex} | 42 +++++++++++++++++--
lib/pleroma/web/auth/pleroma_authenticator.ex | 9 +++-
lib/pleroma/web/oauth/oauth_controller.ex | 31 ++------------
4 files changed, 55 insertions(+), 32 deletions(-)
rename lib/pleroma/{ldap.ex => web/auth/ldap_authenticator.ex} (68%)
diff --git a/docs/config.md b/docs/config.md
index d7349d54f..8d6770959 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -336,3 +336,8 @@ config :auto_linker,
* `sslopts`: additional SSL options
* `base`: LDAP base, e.g. "dc=example,dc=com"
* `uid`: attribute type 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
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
similarity index 68%
rename from lib/pleroma/ldap.ex
rename to lib/pleroma/web/auth/ldap_authenticator.ex
index 282d8e553..56f2f5aed 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -2,15 +2,51 @@
# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.LDAP do
+defmodule Pleroma.Web.Auth.LDAPAuthenticator do
alias Pleroma.User
require Logger
+ @behaviour Pleroma.Web.Auth.Authenticator
+
@connection_timeout 10_000
@search_timeout 10_000
- def get_user(name, password) do
+ def get_user(%Plug.Conn{} = conn) do
+ if Pleroma.Config.get([:ldap, :enabled]) do
+ {name, password} =
+ case conn.params do
+ %{"authorization" => %{"name" => name, "password" => password}} ->
+ {name, password}
+
+ %{"grant_type" => "password", "username" => name, "password" => password} ->
+ {name, password}
+ end
+
+ case ldap_user(name, password) do
+ %User{} = user ->
+ {:ok, user}
+
+ {:error, {:ldap_connection_error, _}} ->
+ # When LDAP is unavailable, try default authenticator
+ Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
+
+ error ->
+ error
+ end
+ else
+ # Fall back to default authenticator
+ Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
+ end
+ end
+
+ def handle_error(%Plug.Conn{} = _conn, error) do
+ error
+ end
+
+ def auth_template, do: nil
+
+ defp ldap_user(name, password) do
ldap = Pleroma.Config.get(:ldap, [])
host = Keyword.get(ldap, :host, "localhost")
port = Keyword.get(ldap, :port, 389)
@@ -50,7 +86,7 @@ def get_user(name, password) do
end
end
- def register_user(connection, base, uid, name, password) do
+ defp register_user(connection, base, uid, name, password) do
case :eldap.search(connection, [
{:base, to_charlist(base)},
{:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 3cc19af01..360772895 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -9,7 +9,14 @@ 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
+ {name, password} =
+ case conn.params do
+ %{"authorization" => %{"name" => name, "password" => password}} ->
+ {name, password}
+
+ %{"grant_type" => "password", "username" => name, "password" => password} ->
+ {name, password}
+ end
with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index c2b6dd477..7d5a5b9c5 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -11,7 +11,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Web.OAuth.App
alias Pleroma.Repo
alias Pleroma.User
- alias Comeonin.Pbkdf2
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
@@ -126,10 +125,10 @@ def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
def token_exchange(
conn,
- %{"grant_type" => "password", "username" => name, "password" => password} = params
+ %{"grant_type" => "password"} = params
) do
- with %App{} = app <- get_app_from_request(conn, params),
- %User{} = user <- get_user(name, password),
+ 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)},
scopes <- oauth_scopes(params, app.scopes),
[] <- scopes -- app.scopes,
@@ -213,28 +212,4 @@ defp get_app_from_request(conn, params) do
nil
end
end
-
- defp get_user(name, password) do
- if Pleroma.Config.get([:ldap, :enabled]) do
- case Pleroma.LDAP.get_user(name, password) do
- %User{} = user ->
- user
-
- {:error, {:ldap_connection_error, _}} ->
- # When LDAP is unavailable, try default login
- with %User{} = user <- User.get_by_nickname_or_email(name),
- true <- Pbkdf2.checkpw(password, user.password_hash) do
- user
- end
-
- error ->
- error
- end
- else
- with %User{} = user <- User.get_by_nickname_or_email(name),
- true <- Pbkdf2.checkpw(password, user.password_hash) do
- user
- end
- end
- end
end
From 818a7894da13c10961a411bd2876f74e74494495 Mon Sep 17 00:00:00 2001
From: William Pearson
Date: Sun, 20 Jan 2019 04:28:34 +0000
Subject: [PATCH 067/184] Don't stream muted accounts
---
lib/pleroma/web/streamer.ex | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 477481bb9..27e8020f4 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -197,10 +197,12 @@ def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = ite
if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || []
+ mutes = user.info.mutes || []
parent = Object.normalize(item.data["object"])
- unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do
+ unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
+ parent.data["actor"] in blocks or parent.data["actor"] in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
else
@@ -224,8 +226,9 @@ def push_to_socket(topics, topic, item) do
if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || []
+ mutes = user.info.mutes || []
- unless item.actor in blocks do
+ unless item.actor in blocks or item.actor in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
else
From 594694607cce6e6afc8261911e44273cb3cb03c0 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Mon, 4 Mar 2019 00:50:00 +0300
Subject: [PATCH 068/184] Unify Mastodon and Twitter follow implementations
using CommonAPI
---
lib/pleroma/web/common_api/common_api.ex | 13 +++++++++++++
.../web/mastodon_api/mastodon_api_controller.ex | 12 ++----------
lib/pleroma/web/twitter_api/twitter_api.ex | 14 ++------------
.../twitter_api/twitter_api_controller_test.exs | 4 ----
4 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 7114d6de6..55a9c2572 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -14,6 +14,19 @@ defmodule Pleroma.Web.CommonAPI do
import Pleroma.Web.CommonAPI.Utils
+ def follow(follower, followed) do
+ with {:ok, follower} <- User.maybe_direct_follow(follower, followed),
+ {:ok, activity} <- ActivityPub.follow(follower, followed),
+ {:ok, follower, followed} <-
+ User.wait_and_refresh(
+ Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
+ follower,
+ followed
+ ) do
+ {:ok, follower, followed, activity}
+ end
+ end
+
def delete(activity_id, user) do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.normalize(object_id),
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 056be49b0..cad5a8fdd 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -733,14 +733,7 @@ def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) d
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with %User{} = followed <- Repo.get(User, id),
- {:ok, follower} <- User.maybe_direct_follow(follower, followed),
- {:ok, _activity} <- ActivityPub.follow(follower, followed),
- {:ok, follower, followed} <-
- User.wait_and_refresh(
- Config.get([:activitypub, :follow_handshake_timeout]),
- follower,
- followed
- ) do
+ {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
@@ -754,8 +747,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
with %User{} = followed <- Repo.get_by(User, nickname: uri),
- {:ok, follower} <- User.maybe_direct_follow(follower, followed),
- {:ok, _activity} <- ActivityPub.follow(follower, followed) do
+ {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("account.json", %{user: followed, for: follower})
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index ab6470d78..dcb15b9a9 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -28,18 +28,8 @@ def delete(%User{} = user, id) do
end
def follow(%User{} = follower, params) do
- with {:ok, %User{} = followed} <- get_user(params),
- {:ok, follower} <- User.maybe_direct_follow(follower, followed),
- {:ok, activity} <- ActivityPub.follow(follower, followed),
- {:ok, follower, followed} <-
- User.wait_and_refresh(
- Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
- follower,
- followed
- ) do
- {:ok, follower, followed, activity}
- else
- err -> err
+ with {:ok, %User{} = followed} <- get_user(params) do
+ CommonAPI.follow(follower, followed)
end
end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index d18b65876..fd76121e3 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1762,8 +1762,6 @@ test "it approves a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == true
@@ -1787,8 +1785,6 @@ test "it denies a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == false
From 86e4b48a5e053f7fc949c682c1d5c0c820b0dd58 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Mon, 4 Mar 2019 02:59:54 +0300
Subject: [PATCH 069/184] Fix DM visibility for blocking users
---
.../mastodon_api/mastodon_api_controller.ex | 15 +++++----
.../web/twitter_api/twitter_api_controller.ex | 15 +++++----
.../mastodon_api_controller_test.exs | 27 ++++++++++++++++
.../twitter_api_controller_test.exs | 31 ++++++++++++++++---
4 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 056be49b0..66d450251 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -292,13 +292,16 @@ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
end
def dm_timeline(%{assigns: %{user: user}} = conn, params) do
- query =
- ActivityPub.fetch_activities_query(
- [user.ap_id],
- Map.merge(params, %{"type" => "Create", visibility: "direct"})
- )
+ params =
+ params
+ |> Map.put("type", "Create")
+ |> Map.put("blocking_user", user)
+ |> Map.put("user", user)
+ |> Map.put(:visibility, "direct")
- activities = Repo.all(query)
+ activities =
+ ActivityPub.fetch_activities_query([user.ap_id], params)
+ |> Repo.all()
conn
|> add_link_headers(:dm_timeline, activities)
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index de7b9f24c..5e4ebb8e8 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -177,13 +177,16 @@ def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
end
def dm_timeline(%{assigns: %{user: user}} = conn, params) do
- query =
- ActivityPub.fetch_activities_query(
- [user.ap_id],
- Map.merge(params, %{"type" => "Create", "user" => user, visibility: "direct"})
- )
+ params =
+ params
+ |> Map.put("type", "Create")
+ |> Map.put("blocking_user", user)
+ |> Map.put("user", user)
+ |> Map.put(:visibility, "direct")
- activities = Repo.all(query)
+ activities =
+ ActivityPub.fetch_activities_query([user.ap_id], params)
+ |> Repo.all()
conn
|> put_view(ActivityView)
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index f7f10662a..ec6869db9 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -248,6 +248,33 @@ test "direct timeline", %{conn: conn} do
assert status["url"] != direct.data["id"]
end
+ test "doesn't include DMs from blocked users", %{conn: conn} do
+ blocker = insert(:user)
+ blocked = insert(:user)
+ user = insert(:user)
+ {:ok, blocker} = User.block(blocker, blocked)
+
+ {:ok, _blocked_direct} =
+ CommonAPI.post(blocked, %{
+ "status" => "Hi @#{blocker.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, direct} =
+ CommonAPI.post(user, %{
+ "status" => "Hi @#{blocker.nickname}!",
+ "visibility" => "direct"
+ })
+
+ res_conn =
+ conn
+ |> assign(:user, user)
+ |> get("api/v1/timelines/direct")
+
+ [status] = json_response(res_conn, 200)
+ assert status["id"] == direct.id
+ end
+
test "replying to a status", %{conn: conn} do
user = insert(:user)
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index d18b65876..ce0812308 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -415,6 +415,33 @@ test "it show direct messages", %{conn: conn} do
assert status["id"] == direct_two.id
assert status_two["id"] == direct.id
end
+
+ test "doesn't include DMs from blocked users", %{conn: conn} do
+ blocker = insert(:user)
+ blocked = insert(:user)
+ user = insert(:user)
+ {:ok, blocker} = User.block(blocker, blocked)
+
+ {:ok, _blocked_direct} =
+ CommonAPI.post(blocked, %{
+ "status" => "Hi @#{blocker.nickname}!",
+ "visibility" => "direct"
+ })
+
+ {:ok, direct} =
+ CommonAPI.post(user, %{
+ "status" => "Hi @#{blocker.nickname}!",
+ "visibility" => "direct"
+ })
+
+ res_conn =
+ conn
+ |> assign(:user, blocker)
+ |> get("/api/statuses/dm_timeline.json")
+
+ [status] = json_response(res_conn, 200)
+ assert status["id"] == direct.id
+ end
end
describe "GET /statuses/mentions.json" do
@@ -1762,8 +1789,6 @@ test "it approves a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == true
@@ -1787,8 +1812,6 @@ test "it denies a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == false
From 8302cdb5dc2b2f74d87f7b36a5ed67e29ea129c0 Mon Sep 17 00:00:00 2001
From: Karen Konou
Date: Mon, 4 Mar 2019 10:47:04 +0100
Subject: [PATCH 070/184] Expand "to" of delete activities
---
lib/pleroma/web/activity_pub/activity_pub.ex | 5 ++++-
test/web/activity_pub/activity_pub_test.exs | 10 ++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 8d3116839..3650d330a 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -305,11 +305,14 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
+ to = object.data["to"] || [] ++ object.data["cc"] ||
+ [] ++ [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
+
data = %{
"type" => "Delete",
"actor" => actor,
"object" => id,
- "to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
+ "to" => Enum.uniq(to)
}
with {:ok, _} <- Object.delete(object),
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index a6f8b822a..0abb18303 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -591,6 +591,16 @@ test "it creates a delete activity and deletes the original object" do
assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end
+
+ test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
+ user = insert(:user)
+ note = insert(:note_activity)
+ object = Object.get_by_ap_id(note.data["object"]["id"])
+ object = Kernel.put_in(object.data["to"], [user.ap_id])
+ {:ok, delete} = ActivityPub.delete(object)
+
+ assert user.ap_id in delete.data["to"]
+ end
end
describe "timeline post-processing" do
From aab86698a5356e26fe68c650f277913497aac3e9 Mon Sep 17 00:00:00 2001
From: Karen Konou
Date: Mon, 4 Mar 2019 10:47:04 +0100
Subject: [PATCH 071/184] Expand "to" of delete activities
---
lib/pleroma/web/activity_pub/activity_pub.ex | 5 ++++-
test/web/activity_pub/activity_pub_test.exs | 10 ++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 783491b67..bff3025ed 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -310,11 +310,14 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
+ to = object.data["to"] || [] ++ object.data["cc"] ||
+ [] ++ [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
+
data = %{
"type" => "Delete",
"actor" => actor,
"object" => id,
- "to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
+ "to" => Enum.uniq(to)
}
with {:ok, _} <- Object.delete(object),
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index f4029896c..e607c7f4d 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -691,6 +691,16 @@ test "decrements user note count only for public activities" do
user = Repo.get(User, user.id)
assert user.info.note_count == 10
end
+
+ test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
+ user = insert(:user)
+ note = insert(:note_activity)
+ object = Object.get_by_ap_id(note.data["object"]["id"])
+ object = Kernel.put_in(object.data["to"], [user.ap_id])
+ {:ok, delete} = ActivityPub.delete(object)
+
+ assert user.ap_id in delete.data["to"]
+ end
end
describe "timeline post-processing" do
From 1445dc25d451f1146acd58ba596ebf5bf37ce6f5 Mon Sep 17 00:00:00 2001
From: Karen Konou
Date: Mon, 4 Mar 2019 11:18:16 +0100
Subject: [PATCH 072/184] fix format
---
lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index bff3025ed..98639883e 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -310,7 +310,8 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
- to = object.data["to"] || [] ++ object.data["cc"] ||
+ to =
+ object.data["to"] || [] ++ object.data["cc"] ||
[] ++ [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
data = %{
From b57913b13ad07cfaa345f7d1e964cd37e5545aa5 Mon Sep 17 00:00:00 2001
From: KokaKiwi
Date: Sun, 3 Mar 2019 18:33:02 +0100
Subject: [PATCH 073/184] Fix supported TLS versions as TLS 1.3 support seems
buggy.
---
config/config.exs | 9 ++++++++-
lib/pleroma/http/http.ex | 7 +++++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/config/config.exs b/config/config.exs
index a620e7451..e6a21104c 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -133,7 +133,14 @@
config :tesla, adapter: Tesla.Adapter.Hackney
# Configures http settings, upstream proxy etc.
-config :pleroma, :http, proxy_url: nil
+config :pleroma, :http,
+ proxy_url: nil,
+ adapter: [
+ ssl_options: [
+ # We don't support TLS v1.3 yet
+ versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]
+ ]
+ ]
config :pleroma, :instance,
name: "Pleroma",
diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex
index 75c58e6c9..26214ef3f 100644
--- a/lib/pleroma/http/http.ex
+++ b/lib/pleroma/http/http.ex
@@ -30,6 +30,7 @@ def request(method, url, body \\ "", headers \\ [], options \\ []) do
options =
process_request_options(options)
|> process_sni_options(url)
+ |> process_adapter_options()
params = Keyword.get(options, :params, [])
@@ -56,6 +57,12 @@ defp process_sni_options(options, url) do
end
end
+ def process_adapter_options(options) do
+ adapter_options = Pleroma.Config.get([:http, :adapter], [])
+
+ options ++ [adapter: adapter_options]
+ end
+
def process_request_options(options) do
config = Application.get_env(:pleroma, :http, [])
proxy = Keyword.get(config, :proxy_url, nil)
From bf43f055ddbfdd8be065eace43de1a742674b1bc Mon Sep 17 00:00:00 2001
From: KokaKiwi
Date: Mon, 18 Feb 2019 00:21:13 +0100
Subject: [PATCH 074/184] Set content types settings on mastofe endpoint.
---
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 056be49b0..2874dfb6d 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1128,7 +1128,8 @@ def index(%{assigns: %{user: user}} = conn, _params) do
compose: %{
me: "#{user.id}",
default_privacy: user.info.default_scope,
- default_sensitive: false
+ default_sensitive: false,
+ allow_content_types: Config.get([:instance, :allowed_post_formats])
},
media_attachments: %{
accept_content_types: [
From 33c614bce002ff27cedbe3969f587c800744b997 Mon Sep 17 00:00:00 2001
From: rinpatch
Date: Mon, 4 Mar 2019 18:09:58 +0300
Subject: [PATCH 075/184] Stop adresssing like activities to actor's follower
collection on non-public posts
---
lib/pleroma/web/activity_pub/utils.ex | 25 ++++++++++++--
test/web/activity_pub/utils_test.exs | 50 +++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 88f4779c8..9e50789db 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Web
alias Pleroma.Object
alias Pleroma.Activity
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.User
alias Pleroma.Notification
alias Pleroma.Web.Router.Helpers
@@ -274,13 +275,31 @@ def get_object_likes(%{data: %{"id" => id}}) do
Repo.all(query)
end
- def make_like_data(%User{ap_id: ap_id} = actor, %{data: %{"id" => id}} = object, activity_id) do
+ def make_like_data(
+ %User{ap_id: ap_id} = actor,
+ %{data: %{"actor" => object_actor_id, "id" => id}} = object,
+ activity_id
+ ) do
+ object_actor = User.get_cached_by_ap_id(object_actor_id)
+
+ to =
+ if Visibility.is_public?(object) do
+ [actor.follower_address, object.data["actor"]]
+ else
+ [object.data["actor"]]
+ end
+
+ cc =
+ (object.data["to"] ++ (object.data["cc"] || []))
+ |> List.delete(actor.ap_id)
+ |> List.delete(object_actor.follower_address)
+
data = %{
"type" => "Like",
"actor" => ap_id,
"object" => id,
- "to" => [actor.follower_address, object.data["actor"]],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "to" => to,
+ "cc" => cc,
"context" => object.data["context"]
}
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index aeed0564c..2e5e95795 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -1,7 +1,10 @@
defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase
+ alias Pleroma.Web.CommonAPI
alias Pleroma.Web.ActivityPub.Utils
+ import Pleroma.Factory
+
describe "determine_explicit_mentions()" do
test "works with an object that has mentions" do
object = %{
@@ -54,4 +57,51 @@ test "works with an object that has only IR tags" do
assert Utils.determine_explicit_mentions(object) == []
end
end
+
+ describe "make_like_data" do
+ setup do
+ user = insert(:user)
+ other_user = insert(:user)
+ third_user = insert(:user)
+ [user: user, other_user: other_user, third_user: third_user]
+ end
+
+ test "addresses actor's follower address if the activity is public", %{
+ user: user,
+ other_user: other_user,
+ third_user: third_user
+ } do
+ expected_to = Enum.sort([user.ap_id, other_user.follower_address])
+ expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" =>
+ "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
+ })
+
+ %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
+ assert Enum.sort(to) == expected_to
+ assert Enum.sort(cc) == expected_cc
+ end
+
+ test "does not adress actor's follower address if the activity is not public", %{
+ user: user,
+ other_user: other_user,
+ third_user: third_user
+ } do
+ expected_to = Enum.sort([user.ap_id])
+ expected_cc = [third_user.ap_id]
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
+ "visibility" => "private"
+ })
+
+ %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
+ assert Enum.sort(to) == expected_to
+ assert Enum.sort(cc) == expected_cc
+ end
+ end
end
From cc7b35e0976a44d21c9f43999f42387ad0a87845 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Mon, 4 Mar 2019 20:47:34 +0300
Subject: [PATCH 076/184] Add status text to notifications (mentions and
reposts)
---
lib/pleroma/web/metadata/utils.ex | 4 +-
lib/pleroma/web/push/push.ex | 43 +++++++++++----
mix.exs | 2 +-
mix.lock | 8 +--
test/support/factory.ex | 14 ++---
test/web/push/push_test.exs | 53 +++++++++++++++++++
.../twitter_api_controller_test.exs | 4 --
7 files changed, 101 insertions(+), 27 deletions(-)
create mode 100644 test/web/push/push_test.exs
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
index a166800d4..5fc9c9e7b 100644
--- a/lib/pleroma/web/metadata/utils.ex
+++ b/lib/pleroma/web/metadata/utils.ex
@@ -17,14 +17,14 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|> Formatter.truncate()
end
- def scrub_html_and_truncate(content) when is_binary(content) do
+ def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
content
# html content comes from DB already encoded, decode first and scrub after
|> HtmlEntities.decode()
|> String.replace(~r/ /, " ")
|> HTML.strip_tags()
|> Formatter.demojify()
- |> Formatter.truncate()
+ |> Formatter.truncate(max_length)
end
def attachment_url(url) do
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index ddd4fe037..4979e0c0c 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -7,7 +7,10 @@ defmodule Pleroma.Web.Push do
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.Activity
+ alias Pleroma.Object
alias Pleroma.Web.Push.Subscription
+ alias Pleroma.Web.Metadata.Utils
require Logger
import Ecto.Query
@@ -119,6 +122,37 @@ def handle_cast({:send, _}, state) do
{:noreply, state}
end
+ # Pleroma.Repo.all(Pleroma.Object)
+ # Pleroma.Repo.all(Pleroma.Activity)
+
+ def format_body(
+ %{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
+ actor
+ ) do
+ "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
+ end
+
+ def format_body(
+ %{activity: %{data: %{"type" => "Announce", "object" => activity_id}}},
+ actor
+ ) do
+ %Activity{data: %{"object" => %{"id" => object_id}}} = Activity.get_by_ap_id(activity_id)
+ %Object{data: %{"content" => content}} = Object.get_by_ap_id(object_id)
+
+ "@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
+ end
+
+ def format_body(
+ %{activity: %{data: %{"type" => type}}},
+ actor
+ )
+ when type in ["Follow", "Like"] do
+ case type do
+ "Follow" -> "@#{actor.nickname} has followed you"
+ "Like" -> "@#{actor.nickname} has favorited your post"
+ end
+ end
+
defp format_title(%{activity: %{data: %{"type" => type}}}) do
case type do
"Create" -> "New Mention"
@@ -127,13 +161,4 @@ defp format_title(%{activity: %{data: %{"type" => type}}}) do
"Like" -> "New Favorite"
end
end
-
- defp format_body(%{activity: %{data: %{"type" => type}}}, actor) do
- case type do
- "Create" -> "@#{actor.nickname} has mentioned you"
- "Follow" -> "@#{actor.nickname} has followed you"
- "Announce" -> "@#{actor.nickname} has repeated your post"
- "Like" -> "@#{actor.nickname} has favorited your post"
- end
- end
end
diff --git a/mix.exs b/mix.exs
index 0fe9c6ec3..70b5e4bd6 100644
--- a/mix.exs
+++ b/mix.exs
@@ -76,7 +76,7 @@ defp deps do
{:ex_aws, "~> 2.0"},
{:ex_aws_s3, "~> 2.0"},
{:earmark, "~> 1.3"},
- {:ex_machina, "~> 2.2", only: :test},
+ {:ex_machina, "~> 2.3", only: :test},
{:credo, "~> 0.9.3", only: [:dev, :test]},
{:mock, "~> 0.3.1", only: :test},
{:crypt,
diff --git a/mix.lock b/mix.lock
index 50e742fbd..f43a18564 100644
--- a/mix.lock
+++ b/mix.lock
@@ -14,14 +14,14 @@
"credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
- "decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm"},
+ "decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"},
- "ecto": {:hex, :ecto, "2.2.10", "e7366dc82f48f8dd78fcbf3ab50985ceeb11cb3dc93435147c6e13f2cda0992e", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
+ "ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"},
"ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
"ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
- "ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
+ "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
"ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
"floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"gen_smtp": {:hex, :gen_smtp, "0.13.0", "11f08504c4bdd831dc520b8f84a1dce5ce624474a797394e7aafd3c29f5dcd25", [:rebar3], [], "hexpm"},
@@ -53,7 +53,7 @@
"plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
- "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
+ "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, 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"},
diff --git a/test/support/factory.ex b/test/support/factory.ex
index d1956d1cd..c025aaf21 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -23,7 +23,7 @@ def user_factory do
}
end
- def note_factory do
+ def note_factory(attrs \\ %{}) do
text = sequence(:text, &"This is :moominmamma: note #{&1}")
user = insert(:user)
@@ -46,7 +46,7 @@ def note_factory do
}
%Pleroma.Object{
- data: data
+ data: merge_attributes(data, Map.get(attrs, :data, %{}))
}
end
@@ -95,8 +95,8 @@ def direct_note_activity_factory do
}
end
- def note_activity_factory do
- note = insert(:note)
+ def note_activity_factory(attrs \\ %{}) do
+ note = attrs[:note] || insert(:note)
data = %{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
@@ -135,9 +135,9 @@ def article_activity_factory do
}
end
- def announce_activity_factory do
- note_activity = insert(:note_activity)
- user = insert(:user)
+ def announce_activity_factory(attrs \\ %{}) do
+ note_activity = attrs[:note_activity] || insert(:note_activity)
+ user = attrs[:user] || insert(:user)
data = %{
"type" => "Announce",
diff --git a/test/web/push/push_test.exs b/test/web/push/push_test.exs
new file mode 100644
index 000000000..5fa97531d
--- /dev/null
+++ b/test/web/push/push_test.exs
@@ -0,0 +1,53 @@
+defmodule Pleroma.Web.PushTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.Push
+
+ import Pleroma.Factory
+
+ test "renders body for create activity" do
+ assert Push.format_body(
+ %{
+ activity: %{
+ data: %{
+ "type" => "Create",
+ "object" => %{
+ "content" =>
+ "Lorem ipsum dolor sit amet , consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis."
+ }
+ }
+ }
+ },
+ %{nickname: "Bob"}
+ ) ==
+ "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
+ end
+
+ test "renders body for follow activity" do
+ assert Push.format_body(%{activity: %{data: %{"type" => "Follow"}}}, %{nickname: "Bob"}) ==
+ "@Bob has followed you"
+ end
+
+ test "renders body for announce activity" do
+ user = insert(:user)
+
+ note =
+ insert(:note, %{
+ data: %{
+ "content" =>
+ "Lorem ipsum dolor sit amet , consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis."
+ }
+ })
+
+ note_activity = insert(:note_activity, %{note: note})
+ announce_activity = insert(:announce_activity, %{user: user, note_activity: note_activity})
+
+ assert Push.format_body(%{activity: announce_activity}, user) ==
+ "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
+ end
+
+ test "renders body for like activity" do
+ assert Push.format_body(%{activity: %{data: %{"type" => "Like"}}}, %{nickname: "Bob"}) ==
+ "@Bob has favorited your post"
+ end
+end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index d18b65876..fd76121e3 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1762,8 +1762,6 @@ test "it approves a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == true
@@ -1787,8 +1785,6 @@ test "it denies a friend request" do
|> assign(:user, user)
|> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
- user = Repo.get(User, user.id)
-
assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"]
assert relationship["follows_you"] == false
From 0245ce842fad4dd53f3c6f6e4a146fc857e8eb1d Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Mon, 4 Mar 2019 20:49:20 +0300
Subject: [PATCH 077/184] Remove unused code
---
lib/pleroma/web/push/push.ex | 3 ---
1 file changed, 3 deletions(-)
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index 4979e0c0c..92f8f9ab4 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -122,9 +122,6 @@ def handle_cast({:send, _}, state) do
{:noreply, state}
end
- # Pleroma.Repo.all(Pleroma.Object)
- # Pleroma.Repo.all(Pleroma.Activity)
-
def format_body(
%{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
actor
From f62019983605dd9af9017351a59b52807bb74ba1 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Mon, 4 Mar 2019 21:26:32 +0300
Subject: [PATCH 078/184] Merge search endpoint into /users
---
lib/pleroma/user.ex | 47 +++++++-----
.../web/admin_api/admin_api_controller.ex | 33 +++++----
lib/pleroma/web/router.ex | 1 -
.../admin_api/admin_api_controller_test.exs | 73 +++++++++++++------
4 files changed, 97 insertions(+), 57 deletions(-)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 50e7e7ccd..3878e4efa 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -749,13 +749,41 @@ def get_recipients_from_activity(%Activity{recipients: to}) do
Repo.all(query)
end
- @spec search_for_admin(binary(), %{
+ @spec search_for_admin(%{
+ local: boolean(),
+ page: number(),
+ page_size: number()
+ }) :: {:ok, [Pleroma.User.t()], number()}
+ def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
+ query =
+ from(u in User, order_by: u.id)
+ |> maybe_local_user_query(local)
+
+ paginated_query =
+ query
+ |> paginate(page, page_size)
+
+ count =
+ query
+ |> Repo.aggregate(:count, :id)
+
+ {:ok, Repo.all(paginated_query), count}
+ end
+
+ @spec search_for_admin(%{
+ query: binary(),
admin: Pleroma.User.t(),
local: boolean(),
page: number(),
page_size: number()
}) :: {:ok, [Pleroma.User.t()], number()}
- def search_for_admin(term, %{admin: admin, local: local, page: page, page_size: page_size}) do
+ def search_for_admin(%{
+ query: term,
+ admin: admin,
+ local: local,
+ page: page,
+ page_size: page_size
+ }) do
term = String.trim_leading(term, "@")
local_paginated_query =
@@ -774,21 +802,6 @@ def search_for_admin(term, %{admin: admin, local: local, page: page, page_size:
{:ok, do_search(search_query, admin), count}
end
- @spec all_for_admin(number(), number()) :: {:ok, [Pleroma.User.t()], number()}
- def all_for_admin(page, page_size) do
- query = from(u in User, order_by: u.id)
-
- paginated_query =
- query
- |> paginate(page, page_size)
-
- count =
- query
- |> Repo.aggregate(:count, :id)
-
- {:ok, Repo.all(paginated_query), count}
- end
-
def search(query, resolve \\ false, for_user \\ nil) do
# Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@")
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index aae02cab8..12b36a1c0 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -63,28 +63,29 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
do: json_response(conn, :no_content, "")
end
- def list_users(conn, params) do
- {page, page_size} = page_params(params)
+ # def list_users(conn, params) do
+ # {page, page_size} = page_params(params)
- with {:ok, users, count} <- User.all_for_admin(page, page_size),
- do:
- conn
- |> json(
- AccountView.render("index.json",
- users: users,
- count: count,
- page_size: page_size
- )
- )
- end
+ # with {:ok, users, count} <- User.all_for_admin(page, page_size),
+ # do:
+ # conn
+ # |> json(
+ # AccountView.render("index.json",
+ # users: users,
+ # count: count,
+ # page_size: page_size
+ # )
+ # )
+ # end
- def search_users(%{assigns: %{user: admin}} = conn, %{"query" => query} = params) do
+ def list_users(%{assigns: %{user: admin}} = conn, params) do
{page, page_size} = page_params(params)
with {:ok, users, count} <-
- User.search_for_admin(query, %{
+ User.search_for_admin(%{
+ query: params["query"],
admin: admin,
- local: params["local"] == "true",
+ local: params["local_only"] == "true",
page: page,
page_size: page_size
}),
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 6fcb46878..3b1fd46a5 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -140,7 +140,6 @@ defmodule Pleroma.Web.Router do
pipe_through([:admin_api, :oauth_write])
get("/users", AdminAPIController, :list_users)
- get("/users/search", AdminAPIController, :search_users)
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 42e0daf8e..dd40b4a06 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -374,26 +374,7 @@ test "renders empty array for the second page" do
"users" => []
}
end
- end
- test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
- admin = insert(:user, info: %{is_admin: true})
- user = insert(:user)
-
- conn =
- build_conn()
- |> assign(:user, admin)
- |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
-
- assert json_response(conn, 200) ==
- %{
- "deactivated" => !user.info.deactivated,
- "id" => user.id,
- "nickname" => user.nickname
- }
- end
-
- describe "GET /api/pleroma/admin/users/search" do
test "regular search" do
admin = insert(:user, info: %{is_admin: true})
user = insert(:user, nickname: "bob")
@@ -401,7 +382,7 @@ test "regular search" do
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users/search?query=bo")
+ |> get("/api/pleroma/admin/users?query=bo")
assert json_response(conn, 200) == %{
"count" => 1,
@@ -424,7 +405,7 @@ test "regular search with page size" do
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users/search?query=bo&page_size=1&page=1")
+ |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=1")
assert json_response(conn, 200) == %{
"count" => 2,
@@ -441,7 +422,7 @@ test "regular search with page size" do
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users/search?query=bo&page_size=1&page=2")
+ |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=2")
assert json_response(conn, 200) == %{
"count" => 2,
@@ -465,7 +446,7 @@ test "only local users" do
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users/search?query=bo&local=true")
+ |> get("/api/pleroma/admin/users?query=bo&local_only=true")
assert json_response(conn, 200) == %{
"count" => 1,
@@ -479,5 +460,51 @@ test "only local users" do
]
}
end
+
+ test "only local users with no query" do
+ admin = insert(:user, info: %{is_admin: true}, nickname: "john")
+ user = insert(:user, nickname: "bob")
+
+ insert(:user, nickname: "bobb", local: false)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> get("/api/pleroma/admin/users?local_only=true")
+
+ assert json_response(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => admin.info.deactivated,
+ "id" => admin.id,
+ "nickname" => admin.nickname
+ },
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
+ ]
+ }
+ end
+ end
+
+ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
+ admin = insert(:user, info: %{is_admin: true})
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
+
+ assert json_response(conn, 200) ==
+ %{
+ "deactivated" => !user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname
+ }
end
end
From d38d537beebd1efe61778b2a26ecab0bed84d1c1 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Sun, 24 Feb 2019 19:13:46 +0000
Subject: [PATCH 079/184] rich media: don't crawl bogus URIs
---
lib/pleroma/web/rich_media/helpers.ex | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index abb1cf7f2..fc9cbc868 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -8,10 +8,17 @@ defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.HTML
alias Pleroma.Web.RichMedia.Parser
+ defp validate_page_url(nil), do: :error
+ defp validate_page_url(%URI{authority: nil}), do: :error
+ defp validate_page_url(%URI{scheme: nil}), do: :error
+ defp validate_page_url(%URI{}), do: :ok
+ defp validate_page_url(page_url), do: URI.parse(page_url) |> validate_page_url
+
def fetch_data_for_activity(%Activity{} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]),
%Object{} = object <- Object.normalize(activity.data["object"]),
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
+ :ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do
%{page_url: page_url, rich_media: rich_media}
else
From d7a278a733616d01ee41c3923a3d87730c685879 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Sun, 24 Feb 2019 19:39:27 +0000
Subject: [PATCH 080/184] tests: add tests for rich media helper functions
---
test/web/rich_media/helpers_test.exs | 42 ++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 test/web/rich_media/helpers_test.exs
diff --git a/test/web/rich_media/helpers_test.exs b/test/web/rich_media/helpers_test.exs
new file mode 100644
index 000000000..9285f078d
--- /dev/null
+++ b/test/web/rich_media/helpers_test.exs
@@ -0,0 +1,42 @@
+defmodule Pleroma.Web.RichMedia.HelpersTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.CommonAPI
+
+ import Pleroma.Factory
+ import Tesla.Mock
+
+ setup do
+ mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ test "refuses to crawl incomplete URLs" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "[test](example.com/ogp)",
+ "content_type" => "text/markdown"
+ })
+
+ assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ end
+
+ test "crawls valid, complete URLs" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "[test](http://example.com/ogp)",
+ "content_type" => "text/markdown"
+ })
+
+ Pleroma.Config.put([:rich_media, :enabled], true)
+
+ assert %{page_url: "http://example.com/ogp", rich_media: _} =
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+
+ Pleroma.Config.put([:rich_media, :enabled], false)
+ end
+end
From 9f3cb38012281c596d1aa8c479f07362fa58dacb Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Sat, 2 Mar 2019 12:22:02 +0000
Subject: [PATCH 081/184] helpers: use AutoLinker to validate URIs as well as
the other tests
---
lib/pleroma/web/rich_media/helpers.ex | 5 ++++-
test/web/rich_media/helpers_test.exs | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index fc9cbc868..ba57171d3 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -12,7 +12,10 @@ defp validate_page_url(nil), do: :error
defp validate_page_url(%URI{authority: nil}), do: :error
defp validate_page_url(%URI{scheme: nil}), do: :error
defp validate_page_url(%URI{}), do: :ok
- defp validate_page_url(page_url), do: URI.parse(page_url) |> validate_page_url
+
+ defp validate_page_url(page_url) do
+ AutoLinker.Parser.is_url?(page_url, true) && URI.parse(page_url) |> validate_page_url
+ end
def fetch_data_for_activity(%Activity{} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]),
diff --git a/test/web/rich_media/helpers_test.exs b/test/web/rich_media/helpers_test.exs
index 9285f078d..60d93768f 100644
--- a/test/web/rich_media/helpers_test.exs
+++ b/test/web/rich_media/helpers_test.exs
@@ -20,7 +20,27 @@ test "refuses to crawl incomplete URLs" do
"content_type" => "text/markdown"
})
+ Pleroma.Config.put([:rich_media, :enabled], true)
+
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+
+ Pleroma.Config.put([:rich_media, :enabled], false)
+ end
+
+ test "refuses to crawl malformed URLs" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "[test](example.com[]/ogp)",
+ "content_type" => "text/markdown"
+ })
+
+ Pleroma.Config.put([:rich_media, :enabled], true)
+
+ assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+
+ Pleroma.Config.put([:rich_media, :enabled], false)
end
test "crawls valid, complete URLs" do
From e34710b9888d5a3602971111c3a376bf8442fb84 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Mon, 4 Mar 2019 21:33:53 +0300
Subject: [PATCH 082/184] Format & update docs
---
docs/Admin-API.md | 35 +++----------------
.../admin_api/admin_api_controller_test.exs | 10 +++---
2 files changed, 10 insertions(+), 35 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 407647645..7f60b768a 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -2,41 +2,16 @@
Authentication is required and the user must be an admin.
-## `/api/pleroma/admin/users`
+## `/api/pleroma/admin/users?query={query}&local={local}&page={page}&page_size={page_size}`
### List users
- Method `GET`
- Params:
- - `page`: **integer** page number
- - `page_size`: **integer** number of users per page (default is `50`)
-- Response:
-
-```JSON
-{
- "page_size": integer,
- "count": integer,
- "users": [
- {
- "deactivated": bool,
- "id": integer,
- "nickname": string
- },
- ...
- ]
-}
-```
-
-## `/api/pleroma/admin/users/search?query={query}&local={local}&page={page}&page_size={page_size}`
-
-### Search users by name or nickname
-
-- Method `GET`
-- Params:
- - `query`: **string** search term
- - `local`: **bool** whether to return only local users
- - `page`: **integer** page number
- - `page_size`: **integer** number of users per page (default is `50`)
+ - `query`: **string** *optional* search term
+ - `local`: **bool** *optional* whether to return only local users
+ - `page`: **integer** *optional* page number
+ - `page_size`: **integer** *optional* number of users per page (default is `50`)
- Response:
```JSON
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index dd40b4a06..1b8b4d4b7 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -476,11 +476,11 @@ test "only local users with no query" do
"count" => 2,
"page_size" => 50,
"users" => [
- %{
- "deactivated" => admin.info.deactivated,
- "id" => admin.id,
- "nickname" => admin.nickname
- },
+ %{
+ "deactivated" => admin.info.deactivated,
+ "id" => admin.id,
+ "nickname" => admin.nickname
+ },
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
From 02359d686ca5f7feb1b83d77a35118bd55efdb52 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Mon, 4 Mar 2019 21:36:47 +0300
Subject: [PATCH 083/184] local -> only_local
---
docs/Admin-API.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 7f60b768a..24944440a 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -2,14 +2,14 @@
Authentication is required and the user must be an admin.
-## `/api/pleroma/admin/users?query={query}&local={local}&page={page}&page_size={page_size}`
+## `/api/pleroma/admin/users?query={query}&only_local={only_local}&page={page}&page_size={page_size}`
### List users
- Method `GET`
- Params:
- `query`: **string** *optional* search term
- - `local`: **bool** *optional* whether to return only local users
+ - `only_local`: **bool** *optional* whether to return only local users
- `page`: **integer** *optional* page number
- `page_size`: **integer** *optional* number of users per page (default is `50`)
- Response:
From b7aa1ea9e6ea919b4eab2762b56f7e4b09300189 Mon Sep 17 00:00:00 2001
From: William Pitcock
Date: Mon, 4 Mar 2019 18:38:23 +0000
Subject: [PATCH 084/184] rich media: helpers: rework validate_page_url()
---
lib/pleroma/web/rich_media/helpers.ex | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index ba57171d3..8317a1162 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -8,14 +8,18 @@ defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.HTML
alias Pleroma.Web.RichMedia.Parser
- defp validate_page_url(nil), do: :error
+ defp validate_page_url(page_url) when is_binary(page_url) do
+ if AutoLinker.Parser.is_url?(page_url, true) do
+ URI.parse(page_url) |> validate_page_url
+ else
+ :error
+ end
+ end
+
defp validate_page_url(%URI{authority: nil}), do: :error
defp validate_page_url(%URI{scheme: nil}), do: :error
defp validate_page_url(%URI{}), do: :ok
-
- defp validate_page_url(page_url) do
- AutoLinker.Parser.is_url?(page_url, true) && URI.parse(page_url) |> validate_page_url
- end
+ defp validate_page_url(_), do: :error
def fetch_data_for_activity(%Activity{} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]),
From 2d30fc279f2a3a5af68918c32c474a2fe8eaf664 Mon Sep 17 00:00:00 2001
From: Maxim Filippov
Date: Tue, 5 Mar 2019 02:11:15 +0300
Subject: [PATCH 085/184] Typo
---
docs/Admin-API.md | 2 +-
lib/pleroma/web/admin_api/admin_api_controller.ex | 15 ---------------
2 files changed, 1 insertion(+), 16 deletions(-)
diff --git a/docs/Admin-API.md b/docs/Admin-API.md
index 24944440a..64e112f9b 100644
--- a/docs/Admin-API.md
+++ b/docs/Admin-API.md
@@ -9,7 +9,7 @@ Authentication is required and the user must be an admin.
- Method `GET`
- Params:
- `query`: **string** *optional* search term
- - `only_local`: **bool** *optional* whether to return only local users
+ - `local_only`: **bool** *optional* whether to return only local users
- `page`: **integer** *optional* page number
- `page_size`: **integer** *optional* number of users per page (default is `50`)
- Response:
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 12b36a1c0..75c2c6061 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -63,21 +63,6 @@ def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
do: json_response(conn, :no_content, "")
end
- # def list_users(conn, params) do
- # {page, page_size} = page_params(params)
-
- # with {:ok, users, count} <- User.all_for_admin(page, page_size),
- # do:
- # conn
- # |> json(
- # AccountView.render("index.json",
- # users: users,
- # count: count,
- # page_size: page_size
- # )
- # )
- # end
-
def list_users(%{assigns: %{user: admin}} = conn, params) do
{page, page_size} = page_params(params)
From d1de0a30ccbc33a45b5b164e1cb910f4717296e9 Mon Sep 17 00:00:00 2001
From: eugenijm
Date: Mon, 4 Mar 2019 22:14:04 +0300
Subject: [PATCH 086/184] Include admins in nodeinfo
---
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 4 +---
test/web/node_info_test.exs | 6 ++++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index f4867d05b..8c775ce24 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
use Pleroma.Web, :controller
alias Pleroma.Config
- alias Pleroma.Repo
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
@@ -86,8 +85,7 @@ def raw_nodeinfo do
end
staff_accounts =
- User.moderator_user_query()
- |> Repo.all()
+ User.all_superusers()
|> Enum.map(fn u -> u.ap_id end)
mrf_user_allowlist =
diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs
index 763549bd1..038feecc1 100644
--- a/test/web/node_info_test.exs
+++ b/test/web/node_info_test.exs
@@ -8,7 +8,8 @@ defmodule Pleroma.Web.NodeInfoTest do
import Pleroma.Factory
test "nodeinfo shows staff accounts", %{conn: conn} do
- user = insert(:user, %{local: true, info: %{is_moderator: true}})
+ moderator = insert(:user, %{local: true, info: %{is_moderator: true}})
+ admin = insert(:user, %{local: true, info: %{is_admin: true}})
conn =
conn
@@ -16,7 +17,8 @@ test "nodeinfo shows staff accounts", %{conn: conn} do
assert result = json_response(conn, 200)
- assert user.ap_id in result["metadata"]["staffAccounts"]
+ assert moderator.ap_id in result["metadata"]["staffAccounts"]
+ assert admin.ap_id in result["metadata"]["staffAccounts"]
end
test "nodeinfo shows restricted nicknames", %{conn: conn} do
From fc37e5815f25d5669a944d216ffd3725e6a84c11 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Tue, 5 Mar 2019 01:44:24 +0100
Subject: [PATCH 087/184] Plugs.HTTPSecurityPlug: Add static_url to CSP's
connect-src
Closes: https://git.pleroma.social/pleroma/pleroma/merge_requests/469
---
lib/pleroma/plugs/http_security_plug.ex | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex
index 057553e24..f701aaaa5 100644
--- a/lib/pleroma/plugs/http_security_plug.ex
+++ b/lib/pleroma/plugs/http_security_plug.ex
@@ -34,13 +34,16 @@ defp headers do
defp csp_string do
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
- websocket_url = String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")
+ static_url = Pleroma.Web.Endpoint.static_url()
+ websocket_url = String.replace(static_url, "http", "ws")
+
+ connect_src = "connect-src 'self' #{static_url} #{websocket_url}"
connect_src =
if Mix.env() == :dev do
- "connect-src 'self' http://localhost:3035/ " <> websocket_url
+ connect_src <> " http://localhost:3035/"
else
- "connect-src 'self' " <> websocket_url
+ connect_src
end
script_src =
From 788a354ce0cbe91d0430ce48db62cb537e845a6d Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier"
Date: Tue, 5 Mar 2019 02:03:44 +0100
Subject: [PATCH 088/184] Web.RelMe: Fix having other values in rel attr
One example of this is Github which puts a rel="nofollow me" on the
profile link.
---
lib/pleroma/web/rel_me.ex | 3 ++-
test/fixtures/rel_me_anchor_nofollow.html | 14 ++++++++++++++
test/fixtures/rel_me_null.html | 1 +
test/web/rel_me_test.exs | 12 ++++++++++++
4 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 test/fixtures/rel_me_anchor_nofollow.html
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index a07db966f..ab29a36e3 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -28,7 +28,8 @@ defp parse_url(url) do
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
data =
- Floki.attribute(html, "link[rel=me]", "href") ++ Floki.attribute(html, "a[rel=me]", "href")
+ Floki.attribute(html, "link[rel~=me]", "href") ++
+ Floki.attribute(html, "a[rel~=me]", "href")
{:ok, data}
rescue
diff --git a/test/fixtures/rel_me_anchor_nofollow.html b/test/fixtures/rel_me_anchor_nofollow.html
new file mode 100644
index 000000000..c856f0091
--- /dev/null
+++ b/test/fixtures/rel_me_anchor_nofollow.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Blog
+
+
+
+ Lorem ipsum
+ Lorem ipsum dolor sit ameph, …
+ lain’s account
+
+
+
diff --git a/test/fixtures/rel_me_null.html b/test/fixtures/rel_me_null.html
index 57d424b80..5ab5f10c1 100644
--- a/test/fixtures/rel_me_null.html
+++ b/test/fixtures/rel_me_null.html
@@ -8,6 +8,7 @@
Lorem ipsum
Lorem ipsum dolor sit ameph, …
+ lain’s account