Merge branch 'develop' into rename/pleroma_activity_consistency
This commit is contained in:
commit
2de208817c
|
@ -36,6 +36,10 @@ def get_by_ap_id(ap_id) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_by_id(id) do
|
||||||
|
Repo.get(Activity, id)
|
||||||
|
end
|
||||||
|
|
||||||
def by_object_ap_id(ap_id) do
|
def by_object_ap_id(ap_id) do
|
||||||
from(
|
from(
|
||||||
activity in Activity,
|
activity in Activity,
|
||||||
|
|
|
@ -275,11 +275,24 @@ defp build_resp_headers(headers, opts) do
|
||||||
|
|
||||||
defp build_resp_cache_headers(headers, _opts) do
|
defp build_resp_cache_headers(headers, _opts) do
|
||||||
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
|
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
|
||||||
|
has_cache_control? = List.keymember?(headers, "cache-control", 0)
|
||||||
|
|
||||||
if has_cache? do
|
cond do
|
||||||
headers
|
has_cache? && has_cache_control? ->
|
||||||
else
|
headers
|
||||||
List.keystore(headers, "cache-control", 0, {"cache-control", @default_cache_control_header})
|
|
||||||
|
has_cache? ->
|
||||||
|
# There's caching header present but no cache-control -- we need to explicitely override it to public
|
||||||
|
# as Plug defaults to "max-age=0, private, must-revalidate"
|
||||||
|
List.keystore(headers, "cache-control", 0, {"cache-control", "public"})
|
||||||
|
|
||||||
|
true ->
|
||||||
|
List.keystore(
|
||||||
|
headers,
|
||||||
|
"cache-control",
|
||||||
|
0,
|
||||||
|
{"cache-control", @default_cache_control_header}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,18 +27,47 @@ defmodule Pleroma.Uploaders.Uploader do
|
||||||
This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL.
|
This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL.
|
||||||
* `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity.
|
* `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity.
|
||||||
* `{:error, String.t}` error information if the file failed to be saved to the backend.
|
* `{:error, String.t}` error information if the file failed to be saved to the backend.
|
||||||
|
* `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@type file_spec :: {:file | :url, String.t()}
|
||||||
@callback put_file(Pleroma.Upload.t()) ::
|
@callback put_file(Pleroma.Upload.t()) ::
|
||||||
:ok | {:ok, {:file | :url, String.t()}} | {:error, String.t()}
|
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
|
||||||
|
|
||||||
|
@callback http_callback(Plug.Conn.t(), Map.t()) ::
|
||||||
|
{:ok, Plug.Conn.t()}
|
||||||
|
| {:ok, Plug.Conn.t(), file_spec()}
|
||||||
|
| {:error, Plug.Conn.t(), String.t()}
|
||||||
|
@optional_callbacks http_callback: 2
|
||||||
|
|
||||||
|
@spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
|
||||||
|
|
||||||
@spec put_file(module(), Pleroma.Upload.t()) ::
|
|
||||||
{:ok, {:file | :url, String.t()}} | {:error, String.t()}
|
|
||||||
def put_file(uploader, upload) do
|
def put_file(uploader, upload) do
|
||||||
case uploader.put_file(upload) do
|
case uploader.put_file(upload) do
|
||||||
:ok -> {:ok, {:file, upload.path}}
|
:ok -> {:ok, {:file, upload.path}}
|
||||||
other -> other
|
:wait_callback -> handle_callback(uploader, upload)
|
||||||
|
{:ok, _} = ok -> ok
|
||||||
|
{:error, _} = error -> error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_callback(uploader, upload) do
|
||||||
|
:global.register_name({__MODULE__, upload.path}, self())
|
||||||
|
|
||||||
|
receive do
|
||||||
|
{__MODULE__, pid, conn, params} ->
|
||||||
|
case uploader.http_callback(conn, params) do
|
||||||
|
{:ok, conn, ok} ->
|
||||||
|
send(pid, {__MODULE__, conn})
|
||||||
|
{:ok, ok}
|
||||||
|
|
||||||
|
{:error, conn, error} ->
|
||||||
|
send(pid, {__MODULE__, conn})
|
||||||
|
{:error, error}
|
||||||
|
end
|
||||||
|
after
|
||||||
|
30_000 -> {:error, "Uploader callback timeout"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -901,7 +901,7 @@ def local_user_query do
|
||||||
def active_local_user_query do
|
def active_local_user_query do
|
||||||
from(
|
from(
|
||||||
u in local_user_query(),
|
u in local_user_query(),
|
||||||
where: fragment("?->'deactivated' @> 'false'", u.info)
|
where: fragment("not (?->'deactivated' @> 'true')", u.info)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -140,8 +140,9 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d
|
||||||
additional
|
additional
|
||||||
),
|
),
|
||||||
{:ok, activity} <- insert(create_data, local),
|
{:ok, activity} <- insert(create_data, local),
|
||||||
:ok <- maybe_federate(activity),
|
# 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) do
|
{:ok, _actor} <- User.increase_note_count(actor),
|
||||||
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -288,8 +289,9 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru
|
||||||
|
|
||||||
with {:ok, _} <- Object.delete(object),
|
with {:ok, _} <- Object.delete(object),
|
||||||
{:ok, activity} <- insert(data, local),
|
{:ok, activity} <- insert(data, local),
|
||||||
:ok <- maybe_federate(activity),
|
# 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) do
|
{:ok, _actor} <- User.decrease_note_count(user),
|
||||||
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -802,11 +804,23 @@ def fetch_and_contain_remote_object_from_id(id) do
|
||||||
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
||||||
def is_public?(%Object{data: data}), do: is_public?(data)
|
def is_public?(%Object{data: data}), do: is_public?(data)
|
||||||
def is_public?(%Activity{data: data}), do: is_public?(data)
|
def is_public?(%Activity{data: data}), do: is_public?(data)
|
||||||
|
def is_public?(%{"directMessage" => true}), do: false
|
||||||
|
|
||||||
def is_public?(data) do
|
def is_public?(data) do
|
||||||
"https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || []))
|
"https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || []))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_private?(activity) do
|
||||||
|
!is_public?(activity) && Enum.any?(activity.data["to"], &String.contains?(&1, "/followers"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true
|
||||||
|
def is_direct?(%Object{data: %{"directMessage" => true}}), do: true
|
||||||
|
|
||||||
|
def is_direct?(activity) do
|
||||||
|
!is_public?(activity) && !is_private?(activity)
|
||||||
|
end
|
||||||
|
|
||||||
def visible_for_user?(activity, nil) do
|
def visible_for_user?(activity, nil) do
|
||||||
is_public?(activity)
|
is_public?(activity)
|
||||||
end
|
end
|
||||||
|
|
|
@ -93,12 +93,47 @@ def fix_addressing_list(map, field) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_addressing(map) do
|
def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, explicit_mentions) do
|
||||||
map
|
explicit_to =
|
||||||
|
to
|
||||||
|
|> Enum.filter(fn x -> x in explicit_mentions end)
|
||||||
|
|
||||||
|
explicit_cc =
|
||||||
|
to
|
||||||
|
|> Enum.filter(fn x -> x not in explicit_mentions end)
|
||||||
|
|
||||||
|
final_cc =
|
||||||
|
(cc ++ explicit_cc)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|
||||||
|
object
|
||||||
|
|> Map.put("to", explicit_to)
|
||||||
|
|> Map.put("cc", final_cc)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_explicit_addressing(object, _explicit_mentions), do: object
|
||||||
|
|
||||||
|
# if directMessage flag is set to true, leave the addressing alone
|
||||||
|
def fix_explicit_addressing(%{"directMessage" => true} = object), do: object
|
||||||
|
|
||||||
|
def fix_explicit_addressing(object) do
|
||||||
|
explicit_mentions =
|
||||||
|
object
|
||||||
|
|> Utils.determine_explicit_mentions()
|
||||||
|
|
||||||
|
explicit_mentions = explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
|
||||||
|
object
|
||||||
|
|> fix_explicit_addressing(explicit_mentions)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fix_addressing(object) do
|
||||||
|
object
|
||||||
|> fix_addressing_list("to")
|
|> fix_addressing_list("to")
|
||||||
|> fix_addressing_list("cc")
|
|> fix_addressing_list("cc")
|
||||||
|> fix_addressing_list("bto")
|
|> fix_addressing_list("bto")
|
||||||
|> fix_addressing_list("bcc")
|
|> fix_addressing_list("bcc")
|
||||||
|
|> fix_explicit_addressing
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix_actor(%{"attributedTo" => actor} = object) do
|
def fix_actor(%{"attributedTo" => actor} = object) do
|
||||||
|
@ -348,6 +383,7 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj
|
||||||
additional:
|
additional:
|
||||||
Map.take(data, [
|
Map.take(data, [
|
||||||
"cc",
|
"cc",
|
||||||
|
"directMessage",
|
||||||
"id"
|
"id"
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,20 @@ def normalize_params(params) do
|
||||||
Map.put(params, "actor", get_ap_id(params["actor"]))
|
Map.put(params, "actor", get_ap_id(params["actor"]))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def determine_explicit_mentions(%{"tag" => tag} = _object) when is_list(tag) do
|
||||||
|
tag
|
||||||
|
|> Enum.filter(fn x -> is_map(x) end)
|
||||||
|
|> Enum.filter(fn x -> x["type"] == "Mention" end)
|
||||||
|
|> Enum.map(fn x -> x["href"] end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def determine_explicit_mentions(%{"tag" => tag} = object) when is_map(tag) do
|
||||||
|
Map.put(object, "tag", [tag])
|
||||||
|
|> determine_explicit_mentions()
|
||||||
|
end
|
||||||
|
|
||||||
|
def determine_explicit_mentions(_), do: []
|
||||||
|
|
||||||
defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll
|
defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll
|
||||||
defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll
|
defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll
|
||||||
defp recipient_in_collection(_, _), do: false
|
defp recipient_in_collection(_, _), do: false
|
||||||
|
|
|
@ -143,7 +143,7 @@ def post(user, %{"status" => status} = data) do
|
||||||
actor: user,
|
actor: user,
|
||||||
context: context,
|
context: context,
|
||||||
object: object,
|
object: object,
|
||||||
additional: %{"cc" => cc}
|
additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
|
||||||
})
|
})
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
|
@ -231,6 +231,9 @@ def get_visibility(object) do
|
||||||
Enum.any?(to, &String.contains?(&1, "/followers")) ->
|
Enum.any?(to, &String.contains?(&1, "/followers")) ->
|
||||||
"private"
|
"private"
|
||||||
|
|
||||||
|
length(cc) > 0 ->
|
||||||
|
"private"
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
"direct"
|
"direct"
|
||||||
end
|
end
|
||||||
|
|
|
@ -107,6 +107,11 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/captcha", UtilController, :captcha)
|
get("/captcha", UtilController, :captcha)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope "/api/pleroma", Pleroma.Web do
|
||||||
|
pipe_through(:pleroma_api)
|
||||||
|
post("/uploader_callback/:upload_path", UploaderController, :callback)
|
||||||
|
end
|
||||||
|
|
||||||
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
|
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
|
||||||
pipe_through(:admin_api)
|
pipe_through(:admin_api)
|
||||||
delete("/user", AdminAPIController, :user_delete)
|
delete("/user", AdminAPIController, :user_delete)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
defmodule Pleroma.Web.UploaderController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Uploaders.Uploader
|
||||||
|
|
||||||
|
def callback(conn, params = %{"upload_path" => upload_path}) do
|
||||||
|
process_callback(conn, :global.whereis_name({Uploader, upload_path}), params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def callbacks(conn, _) do
|
||||||
|
send_resp(conn, 400, "bad request")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_callback(conn, pid, params) when is_pid(pid) do
|
||||||
|
send(pid, {Uploader, self(), conn, params})
|
||||||
|
|
||||||
|
receive do
|
||||||
|
{Uploader, conn} -> conn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_callback(conn, _, _) do
|
||||||
|
send_resp(conn, 400, "bad request")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.UpdateActivityVisibility do
|
||||||
|
use Ecto.Migration
|
||||||
|
@disable_ddl_transaction true
|
||||||
|
|
||||||
|
def up do
|
||||||
|
definition = """
|
||||||
|
create or replace function activity_visibility(actor varchar, recipients varchar[], data jsonb) returns varchar as $$
|
||||||
|
DECLARE
|
||||||
|
fa varchar;
|
||||||
|
public varchar := 'https://www.w3.org/ns/activitystreams#Public';
|
||||||
|
BEGIN
|
||||||
|
SELECT COALESCE(users.follower_address, '') into fa from users where users.ap_id = actor;
|
||||||
|
|
||||||
|
IF data->'to' ? public THEN
|
||||||
|
RETURN 'public';
|
||||||
|
ELSIF data->'cc' ? public THEN
|
||||||
|
RETURN 'unlisted';
|
||||||
|
ELSIF ARRAY[fa] && recipients THEN
|
||||||
|
RETURN 'private';
|
||||||
|
ELSIF not(ARRAY[fa, public] && recipients) THEN
|
||||||
|
RETURN 'direct';
|
||||||
|
ELSE
|
||||||
|
RETURN 'unknown';
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE SECURITY DEFINER;
|
||||||
|
"""
|
||||||
|
|
||||||
|
execute(definition)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,7 +17,9 @@
|
||||||
"toot": "http://joinmastodon.org/ns#",
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
"totalItems": "as:totalItems",
|
"totalItems": "as:totalItems",
|
||||||
"value": "schema:value",
|
"value": "schema:value",
|
||||||
"sensitive": "as:sensitive"
|
"sensitive": "as:sensitive",
|
||||||
|
"litepub": "http://litepub.social/ns#",
|
||||||
|
"directMessage": "litepub:directMessage"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,13 +66,10 @@ test "receives well formatted events" do
|
||||||
assert json["payload"]
|
assert json["payload"]
|
||||||
assert {:ok, json} = Jason.decode(json["payload"])
|
assert {:ok, json} = Jason.decode(json["payload"])
|
||||||
|
|
||||||
# Note: we remove the "statuses_count" from this result as it changes in the meantime
|
|
||||||
|
|
||||||
view_json =
|
view_json =
|
||||||
Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil)
|
Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil)
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|> put_in(["account", "statuses_count"], 0)
|
|
||||||
|
|
||||||
assert json == view_json
|
assert json == view_json
|
||||||
end
|
end
|
||||||
|
|
|
@ -162,6 +162,36 @@ test "it works for incoming notices with url not being a string (prismo)" do
|
||||||
assert data["object"]["url"] == "https://prismo.news/posts/83"
|
assert data["object"]["url"] == "https://prismo.news/posts/83"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it cleans up incoming notices which are not really DMs" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
to = [user.ap_id, other_user.ap_id]
|
||||||
|
|
||||||
|
data =
|
||||||
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|
|> Poison.decode!()
|
||||||
|
|> Map.put("to", to)
|
||||||
|
|> Map.put("cc", [])
|
||||||
|
|
||||||
|
object =
|
||||||
|
data["object"]
|
||||||
|
|> Map.put("to", to)
|
||||||
|
|> Map.put("cc", [])
|
||||||
|
|
||||||
|
data = Map.put(data, "object", object)
|
||||||
|
|
||||||
|
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
|
assert data["to"] == []
|
||||||
|
assert data["cc"] == to
|
||||||
|
|
||||||
|
object = data["object"]
|
||||||
|
|
||||||
|
assert object["to"] == []
|
||||||
|
assert object["cc"] == to
|
||||||
|
end
|
||||||
|
|
||||||
test "it works for incoming follow requests" do
|
test "it works for incoming follow requests" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
@ -872,6 +902,34 @@ test "it adds like collection to object" do
|
||||||
assert modified["object"]["likes"]["type"] == "OrderedCollection"
|
assert modified["object"]["likes"]["type"] == "OrderedCollection"
|
||||||
assert modified["object"]["likes"]["totalItems"] == 0
|
assert modified["object"]["likes"]["totalItems"] == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "the directMessage flag is present" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"})
|
||||||
|
|
||||||
|
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
|
||||||
|
|
||||||
|
assert modified["directMessage"] == false
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"})
|
||||||
|
|
||||||
|
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
|
||||||
|
|
||||||
|
assert modified["directMessage"] == false
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.post(user, %{
|
||||||
|
"status" => "@#{other_user.nickname} :moominmamma:",
|
||||||
|
"visibility" => "direct"
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
|
||||||
|
|
||||||
|
assert modified["directMessage"] == true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "user upgrade" do
|
describe "user upgrade" do
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
defmodule Pleroma.Web.ActivityPub.UtilsTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
|
||||||
|
describe "determine_explicit_mentions()" do
|
||||||
|
test "works with an object that has mentions" do
|
||||||
|
object = %{
|
||||||
|
"tag" => [
|
||||||
|
%{
|
||||||
|
"type" => "Mention",
|
||||||
|
"href" => "https://example.com/~alyssa",
|
||||||
|
"name" => "Alyssa P. Hacker"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "works with an object that does not have mentions" do
|
||||||
|
object = %{
|
||||||
|
"tag" => [
|
||||||
|
%{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Utils.determine_explicit_mentions(object) == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "works with an object that has mentions and other tags" do
|
||||||
|
object = %{
|
||||||
|
"tag" => [
|
||||||
|
%{
|
||||||
|
"type" => "Mention",
|
||||||
|
"href" => "https://example.com/~alyssa",
|
||||||
|
"name" => "Alyssa P. Hacker"
|
||||||
|
},
|
||||||
|
%{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "works with an object that has no tags" do
|
||||||
|
object = %{}
|
||||||
|
|
||||||
|
assert Utils.determine_explicit_mentions(object) == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "works with an object that has only IR tags" do
|
||||||
|
object = %{"tag" => ["2hu"]}
|
||||||
|
|
||||||
|
assert Utils.determine_explicit_mentions(object) == []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|
||||||
alias Pleroma.Web.{OStatus, CommonAPI}
|
alias Pleroma.Web.{OStatus, CommonAPI}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.MastodonAPI.FilterView
|
alias Pleroma.Web.MastodonAPI.FilterView
|
||||||
|
alias Ecto.Changeset
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import ExUnit.CaptureLog
|
import ExUnit.CaptureLog
|
||||||
import Tesla.Mock
|
import Tesla.Mock
|
||||||
|
@ -1483,6 +1484,16 @@ test "get instance information", %{conn: conn} do
|
||||||
|
|
||||||
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
|
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
|
||||||
|
|
||||||
|
# Stats should count users with missing or nil `info.deactivated` value
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
info_change = Changeset.change(user.info, %{deactivated: nil})
|
||||||
|
|
||||||
|
{:ok, _user} =
|
||||||
|
user
|
||||||
|
|> Changeset.change()
|
||||||
|
|> Changeset.put_embed(:info, info_change)
|
||||||
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
Pleroma.Stats.update_stats()
|
Pleroma.Stats.update_stats()
|
||||||
|
|
||||||
conn = get(conn, "/api/v1/instance")
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
Loading…
Reference in New Issue