aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/config.exs10
-rw-r--r--docs/Admin-API.md191
-rw-r--r--docs/config.md27
-rw-r--r--installation/pleroma.nginx7
-rw-r--r--lib/pleroma/formatter.ex198
-rw-r--r--lib/pleroma/user.ex17
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex17
-rw-r--r--lib/pleroma/web/common_api/common_api.ex28
-rw-r--r--lib/pleroma/web/common_api/utils.ex86
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex11
-rw-r--r--lib/pleroma/web/router.ex2
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex21
-rw-r--r--mix.exs5
-rw-r--r--mix.lock1
-rw-r--r--test/formatter_test.exs114
-rw-r--r--test/user_test.exs14
-rw-r--r--test/web/admin_api/admin_api_controller_test.exs35
-rw-r--r--test/web/common_api/common_api_utils_test.exs44
-rw-r--r--test/web/mastodon_api/account_view_test.exs66
-rw-r--r--test/web/twitter_api/views/user_view_test.exs7
20 files changed, 539 insertions, 362 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 @@ config :pleroma, Pleroma.Jobs,
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/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
+
+- 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
+
+```JSON
+{
+ "deactivated": bool,
+ "id": integer,
+ "nickname": string
+}
+```
## `/api/pleroma/admin/users/tag`
+
### Tag a list of users
-* Method: `PUT`
-* Params:
- * `nickname`
- * `tags`
+
+- Method: `PUT`
+- Params:
+ - `nickname`
+ - `tags`
+
### Untag a list of users
-* Method: `DELETE`
-* Params:
- * `nickname`
- * `tags`
+
+- Method: `DELETE`
+- Params:
+ - `nickname`
+ - `tags`
## `/api/pleroma/admin/permission_group/:nickname`
+
### 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
}
```
## `/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/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/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;
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index f31aafa0d..048c032ed 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
-
- 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).()
+ @auto_linker_config hashtag: true,
+ hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
+ mention: true,
+ mention_handler: &Pleroma.Formatter.mention_handler/4
+
+ 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 =
+ "<span class='h-card'><a data-user='#{id}' class='u-url mention' href='#{ap_id}'>@<span>#{
+ nickname_text
+ }</span></a></span>"
+
+ {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 = "<a class='hashtag' data-tag='#{tag}' href='#{url}' rel='tag'>#{tag_text}</a>"
+
+ {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 @@ defmodule Pleroma.Formatter do
emoji = HTML.strip_tags(emoji)
file = HTML.strip_tags(file)
- String.replace(
- text,
- ":#{emoji}:",
+ html =
if not strip do
"<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{
MediaProxy.url(file)
@@ -58,8 +74,8 @@ defmodule Pleroma.Formatter do
else
""
end
- )
- |> HTML.filter_tags()
+
+ String.replace(text, ":#{emoji}:", html) |> HTML.filter_tags()
end)
end
@@ -75,12 +91,10 @@ defmodule Pleroma.Formatter do
def get_emoji(_), do: []
- @link_regex ~r/[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+/ui
-
- @uri_schemes Application.get_env(:pleroma, :uri_schemes, [])
- @valid_schemes Keyword.get(@uri_schemes, :valid_schemes, [])
+ def html_escape({text, mentions, hashtags}, type) do
+ {html_escape(text, type), mentions, hashtags}
+ end
- # TODO: make it use something other than @link_regex
def html_escape(text, "text/html") do
HTML.filter_tags(text)
end
@@ -94,112 +108,6 @@ defmodule Pleroma.Formatter 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", "<br>"])
- |> 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, "<a href=\"#{url}\">#{url}</a>"}
- 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,
- "<span class='h-card'><a data-user='#{id}' class='u-url mention' href='#{ap_id}'>" <>
- "@<span>#{nickname}</span></a></span>"}
- 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 =
- "<a class='hashtag' data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{
- tag_text
- }</a>"
-
- {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 +119,16 @@ defmodule Pleroma.Formatter 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 c98b942ff..c5085fa82 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -613,9 +613,10 @@ defmodule Pleroma.User do
),
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
a.data,
- ^%{"object" => user.ap_id}
+ a.data,
+ ^user.ap_id
)
)
end
@@ -772,6 +773,12 @@ defmodule Pleroma.User 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(
@@ -1187,9 +1194,6 @@ defmodule Pleroma.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)
@@ -1198,7 +1202,8 @@ defmodule Pleroma.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/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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> 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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController 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/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 @@ defmodule Pleroma.Web.CommonAPI do
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 @@ defmodule Pleroma.Web.CommonAPI 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..e4b9102c5 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 @@ defmodule Pleroma.Web.CommonAPI.Utils 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 @@ defmodule Pleroma.Web.CommonAPI.Utils do
Enum.join([text | attachment_text], "<br>")
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/, "<br>")
- |> (&{[], &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/, "<br>"), 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.linkify(options)
+ |> (fn {text, mentions, tags} -> {Earmark.as_html!(text), mentions, tags} end).()
|> 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 = "<a href='#{Web.base_url()}/tag/#{tag}' rel='tag'>##{tag}</a>"
- String.replace(text, full, url)
- end)
end
def make_note_data(
@@ -323,13 +327,13 @@ defmodule Pleroma.Web.CommonAPI.Utils 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/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 @@ defmodule Pleroma.Web.MastodonAPI.AccountView 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountView 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountView 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/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..22f33e0b5 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 @@ defmodule Pleroma.Web.TwitterAPI.UserView 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,
@@ -118,6 +132,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView 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)
}
@@ -134,6 +149,12 @@ defmodule Pleroma.Web.TwitterAPI.UserView 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/mix.exs b/mix.exs
index d78825769..5392d94d1 100644
--- a/mix.exs
+++ b/mix.exs
@@ -90,7 +90,10 @@ defmodule Pleroma.Mixfile 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 @@ defmodule Pleroma.FormatterTest do
expected_text =
"I love <a class='hashtag' data-tag='cofe' href='http://localhost:4001/tag/cofe' rel='tag'>#cofe</a> and <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a>"
- 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 <a class='hashtag' data-tag='3' href='http://localhost:4001/tag/3' rel='tag'>#3</a>: pleroma does what mastodon't"
-
- tags = Formatter.parse_tags(text)
+ "<a class='hashtag' data-tag='fact_3' href='http://localhost:4001/tag/fact_3' rel='tag'>#fact_3</a>: pleroma does what mastodon't"
- assert expected_text ==
- Formatter.add_hashtag_links({[], text}, tags) |> Formatter.finalize()
+ assert {^expected_text, [], _tags} = Formatter.linkify(text)
end
end
@@ -47,79 +41,79 @@ defmodule Pleroma.FormatterTest do
expected =
"Hey, check out <a href=\"https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla\">https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla</a> ."
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://mastodon.social/@lambadalambda"
expected =
"<a href=\"https://mastodon.social/@lambadalambda\">https://mastodon.social/@lambadalambda</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://mastodon.social:4000/@lambadalambda"
expected =
"<a href=\"https://mastodon.social:4000/@lambadalambda\">https://mastodon.social:4000/@lambadalambda</a>"
- 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 = "<a href=\"http://www.cs.vu.nl/~ast/intel/\">http://www.cs.vu.nl/~ast/intel/</a>"
- 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 =
"<a href=\"https://forum.zdoom.org/viewtopic.php?f=44&t=57087\">https://forum.zdoom.org/viewtopic.php?f=44&t=57087</a>"
- 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 =
"<a href=\"https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul\">https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://www.google.co.jp/search?q=Nasim+Aghdam"
expected =
"<a href=\"https://www.google.co.jp/search?q=Nasim+Aghdam\">https://www.google.co.jp/search?q=Nasim+Aghdam</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://en.wikipedia.org/wiki/Duff's_device"
expected =
"<a href=\"https://en.wikipedia.org/wiki/Duff's_device\">https://en.wikipedia.org/wiki/Duff's_device</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "https://pleroma.com https://pleroma.com/sucks"
expected =
"<a href=\"https://pleroma.com\">https://pleroma.com</a> <a href=\"https://pleroma.com/sucks\">https://pleroma.com/sucks</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
text = "xmpp:contact@hacktivis.me"
expected = "<a href=\"xmpp:contact@hacktivis.me\">xmpp:contact@hacktivis.me</a>"
- 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 = "<a href=\"#{text}\">#{text}</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
+ assert {^expected, [], []} = Formatter.linkify(text)
end
end
@@ -136,12 +130,9 @@ defmodule Pleroma.FormatterTest do
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
- mentions = Pleroma.Formatter.parse_mentions(text)
-
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
+ {text, mentions, []} = Formatter.linkify(text)
- assert length(subs) == 3
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
+ assert length(mentions) == 3
expected_text =
"<span class='h-card'><a data-user='#{gsimg.id}' class='u-url mention' href='#{
@@ -152,7 +143,7 @@ defmodule Pleroma.FormatterTest do
archaeme_remote.id
}' class='u-url mention' href='#{archaeme_remote.ap_id}'>@<span>archaeme</span></a></span>"
- 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 @@ defmodule Pleroma.FormatterTest 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 =
"<span class='h-card'><a data-user='#{mike.id}' class='u-url mention' href='#{mike.ap_id}'>@<span>mike</span></a></span> 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)
-
- {subs, text} = Formatter.add_user_links({[], text}, mentions)
+ {text, mentions, []} = Formatter.linkify(text)
- assert length(subs) == 1
- Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
+ assert length(mentions) == 1
expected_text =
"<span class='h-card'><a data-user='#{o.id}' class='u-url mention' href='#{o.ap_id}'>@<span>o</span></a></span> 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 @@ defmodule Pleroma.FormatterTest do
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 @@ defmodule Pleroma.FormatterTest 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 @@ defmodule Pleroma.FormatterTest 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_ ")
- """
-
- 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
+ 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 &amp; world google.com/?a=b&c=d \n http://test.com/?a=b&c=d 1"
+
+ assert Formatter.html_escape(text, "text/plain") == expected
end
end
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 @@ defmodule Pleroma.UserTest 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)
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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest 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
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index faed6b685..684f2a23f 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 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest 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!<br><br>second paragraph!"
- output = Utils.format_input(text, [], [], "text/plain")
+ {output, [], []} = Utils.format_input(text, "text/plain")
assert output == expected
end
@@ -78,14 +78,14 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
text = "<p>hello world!</p>"
expected = "<p>hello world!</p>"
- output = Utils.format_input(text, [], [], "text/html")
+ {output, [], []} = Utils.format_input(text, "text/html")
assert output == expected
text = "<p>hello world!</p>\n\n<p>second paragraph</p>"
expected = "<p>hello world!</p>\n\n<p>second paragraph</p>"
- output = Utils.format_input(text, [], [], "text/html")
+ {output, [], []} = Utils.format_input(text, "text/html")
assert output == expected
end
@@ -94,14 +94,44 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
text = "**hello world**"
expected = "<p><strong>hello world</strong></p>\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 = "<p><strong>hello world</strong></p>\n<p><em>another paragraph</em></p>\n"
- output = Utils.format_input(text, [], [], "text/markdown")
+ {output, [], []} = Utils.format_input(text, "text/markdown")
+
+ assert output == expected
+
+ text = """
+ > cool quote
+
+ by someone
+ """
+
+ expected = "<blockquote><p>cool quote</p>\n</blockquote>\n<p>by someone</p>\n"
+
+ {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 =
+ "<p><strong>hello world</strong></p>\n<p><em>another <span class=\"h-card\"><a data-user=\"#{
+ user.id
+ }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> and <span class=\"h-card\"><a data-user=\"#{
+ user.id
+ }\" class=\"u-url mention\" href=\"http://foo.com/user__test\">@<span>user__test</span></a></span> <a href=\"http://google.com\">google.com</a> paragraph</em></p>\n"
+
+ {output, _, _} = Utils.format_input(text, "text/markdown")
assert output == expected
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 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
confirmation_pending: false,
tags: [],
is_admin: false,
- is_moderator: false
+ is_moderator: false,
+ relationship: %{}
}
}
@@ -106,7 +107,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
confirmation_pending: false,
tags: [],
is_admin: false,
- is_moderator: false
+ is_moderator: false,
+ relationship: %{}
}
}
@@ -148,4 +150,64 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest 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
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 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest 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)