Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms

This commit is contained in:
lain 2020-05-25 13:57:27 +02:00
commit ee35bb5ac2
64 changed files with 1593 additions and 701 deletions

View file

@ -15,12 +15,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **Breaking:** removed `with_move` parameter from notifications timeline. - **Breaking:** removed `with_move` parameter from notifications timeline.
### Added ### Added
- ActivityPub: Added support for existing AP ids for instances migrated from Mastodon.
- Instance: Add `background_image` to configuration and `/api/v1/instance` - Instance: Add `background_image` to configuration and `/api/v1/instance`
- Instance: Extend `/api/v1/instance` with Pleroma-specific information. - Instance: Extend `/api/v1/instance` with Pleroma-specific information.
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list. - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` to the `features` list. - NodeInfo: `pleroma_emoji_reactions` to the `features` list.
- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses. - Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
- Configuration: Add `:database_config_whitelist` setting to whitelist settings which can be configured from AdminFE. - Configuration: Add `:database_config_whitelist` setting to whitelist settings which can be configured from AdminFE.
- Configuration: `filename_display_max_length` option to set filename truncate limit, if filename display enabled (0 = no limit).
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required. - New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required.
- Mix task to create trusted OAuth App. - Mix task to create trusted OAuth App.
- Notifications: Added `follow_request` notification type. - Notifications: Added `follow_request` notification type.

View file

@ -71,7 +71,8 @@ config :pleroma, Pleroma.Upload,
follow_redirect: true, follow_redirect: true,
pool: :upload pool: :upload
] ]
] ],
filename_display_max_length: 30
config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads" config :pleroma, Pleroma.Uploaders.Local, uploads: "uploads"

View file

@ -119,6 +119,11 @@ config :pleroma, :config_description, [
] ]
} }
] ]
},
%{
key: :filename_display_max_length,
type: :integer,
description: "Set max length of a filename to display. 0 = no limit. Default: 30"
} }
] ]
}, },
@ -969,6 +974,13 @@ config :pleroma, :config_description, [
] ]
} }
] ]
},
%{
key: :instance_thumbnail,
type: :string,
description:
"The instance thumbnail image. It will appear in [Pleroma Instances](http://distsn.org/pleroma-instances.html)",
suggestions: ["/instance/thumbnail.jpeg"]
} }
] ]
}, },
@ -1112,7 +1124,7 @@ config :pleroma, :config_description, [
logoMask: true, logoMask: true,
minimalScopesMode: false, minimalScopesMode: false,
noAttachmentLinks: false, noAttachmentLinks: false,
nsfwCensorImage: "", nsfwCensorImage: "/static/img/nsfw.74818f9.png",
postContentType: "text/plain", postContentType: "text/plain",
redirectRootLogin: "/main/friends", redirectRootLogin: "/main/friends",
redirectRootNoLogin: "/main/all", redirectRootNoLogin: "/main/all",
@ -1226,7 +1238,7 @@ config :pleroma, :config_description, [
type: :string, type: :string,
description: description:
"URL of the image to use for hiding NSFW media attachments in the timeline.", "URL of the image to use for hiding NSFW media attachments in the timeline.",
suggestions: ["/static/img/nsfw.png"] suggestions: ["/static/img/nsfw.74818f9.png"]
}, },
%{ %{
key: :postContentType, key: :postContentType,
@ -1346,6 +1358,12 @@ config :pleroma, :config_description, [
suggestions: [ suggestions: [
:pleroma_fox_tan :pleroma_fox_tan
] ]
},
%{
key: :default_user_avatar,
type: :string,
description: "URL of the default user avatar.",
suggestions: ["/images/avi.png"]
} }
] ]
}, },

View file

@ -498,6 +498,7 @@ the source code is here: https://github.com/koto-bank/kocaptcha. The default end
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host. * `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host.
* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it. * `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation. * `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
* `filename_display_max_length`: Set max length of a filename to display. 0 = no limit. Default: 30.
!!! warning !!! warning
`strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`. `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`.

View file

@ -147,6 +147,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
"What directory should media uploads go in (when using the local uploader)?", "What directory should media uploads go in (when using the local uploader)?",
Pleroma.Config.get([Pleroma.Uploaders.Local, :uploads]) Pleroma.Config.get([Pleroma.Uploaders.Local, :uploads])
) )
|> Path.expand()
static_dir = static_dir =
get_option( get_option(
@ -155,6 +156,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
"What directory should custom public files be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)?", "What directory should custom public files be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)?",
Pleroma.Config.get([:instance, :static_dir]) Pleroma.Config.get([:instance, :static_dir])
) )
|> Path.expand()
Config.put([:instance, :static_dir], static_dir) Config.put([:instance, :static_dir], static_dir)
@ -204,7 +206,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
shell_info("Writing the postgres script to #{psql_path}.") shell_info("Writing the postgres script to #{psql_path}.")
File.write(psql_path, result_psql) File.write(psql_path, result_psql)
write_robots_txt(indexable, template_dir) write_robots_txt(static_dir, indexable, template_dir)
shell_info( shell_info(
"\n All files successfully written! Refer to the installation instructions for your platform for next steps." "\n All files successfully written! Refer to the installation instructions for your platform for next steps."
@ -224,15 +226,13 @@ defmodule Mix.Tasks.Pleroma.Instance do
end end
end end
defp write_robots_txt(indexable, template_dir) do defp write_robots_txt(static_dir, indexable, template_dir) do
robots_txt = robots_txt =
EEx.eval_file( EEx.eval_file(
template_dir <> "/robots_txt.eex", template_dir <> "/robots_txt.eex",
indexable: indexable indexable: indexable
) )
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
unless File.exists?(static_dir) do unless File.exists?(static_dir) do
File.mkdir_p!(static_dir) File.mkdir_p!(static_dir)
end end

View file

@ -14,8 +14,10 @@ defmodule Pleroma.Emails.NewUsersDigestEmail do
styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling]) styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling])
logo_url = logo_url =
Pleroma.Web.Endpoint.url() <> Pleroma.Helpers.UriHelper.maybe_add_base(
Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo]) Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo]),
Pleroma.Web.Endpoint.url()
)
new() new()
|> to({to.name, to.email}) |> to({to.name, to.email})

View file

@ -24,4 +24,7 @@ defmodule Pleroma.Helpers.UriHelper do
params params
end end
end end
def maybe_add_base("/" <> uri, base), do: Path.join([base, uri])
def maybe_add_base(uri, _base), do: uri
end end

View file

@ -305,8 +305,13 @@ defmodule Pleroma.User do
def avatar_url(user, options \\ []) do def avatar_url(user, options \\ []) do
case user.avatar do case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href %{"url" => [%{"href" => href} | _]} ->
_ -> !options[:no_default] && "#{Web.base_url()}/images/avi.png" href
_ ->
unless options[:no_default] do
Config.get([:assets, :default_user_avatar], "#{Web.base_url()}/images/avi.png")
end
end end
end end

View file

@ -363,36 +363,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
@spec announce(User.t(), Object.t(), String.t() | nil, boolean(), boolean()) ::
{:ok, Activity.t(), Object.t()} | {:error, any()}
def announce(
%User{ap_id: _} = user,
%Object{data: %{"id" => _}} = object,
activity_id \\ nil,
local \\ true,
public \\ true
) do
with {:ok, result} <-
Repo.transaction(fn -> do_announce(user, object, activity_id, local, public) end) do
result
end
end
defp do_announce(user, object, activity_id, local, public) do
with true <- is_announceable?(object, user, public),
object <- Object.get_by_id(object.id),
announce_data <- make_announce_data(user, object, activity_id, public),
{:ok, activity} <- insert(announce_data, local),
{:ok, object} <- add_announce_to_object(activity, object),
_ <- notify_and_stream(activity),
:ok <- maybe_federate(activity) do
{:ok, activity, object}
else
false -> {:error, false}
{:error, error} -> Repo.rollback(error)
end
end
@spec follow(User.t(), User.t(), String.t() | nil, boolean()) :: @spec follow(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | {:error, any()} {:ok, Activity.t()} | {:error, any()}
def follow(follower, followed, activity_id \\ nil, local \\ true) do def follow(follower, followed, activity_id \\ nil, local \\ true) do

View file

@ -21,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Endpoint
alias Pleroma.Web.FederatingPlug alias Pleroma.Web.FederatingPlug
alias Pleroma.Web.Federator alias Pleroma.Web.Federator
@ -75,8 +76,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end end
end end
def object(conn, %{"uuid" => uuid}) do def object(conn, _) do
with ap_id <- o_status_url(conn, :object, uuid), with ap_id <- Endpoint.url() <> conn.request_path,
%Object{} = object <- Object.get_cached_by_ap_id(ap_id), %Object{} = object <- Object.get_cached_by_ap_id(ap_id),
{_, true} <- {:public?, Visibility.is_public?(object)} do {_, true} <- {:public?, Visibility.is_public?(object)} do
conn conn
@ -101,8 +102,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
conn conn
end end
def activity(conn, %{"uuid" => uuid}) do def activity(conn, _params) do
with ap_id <- o_status_url(conn, :activity, uuid), with ap_id <- Endpoint.url() <> conn.request_path,
%Activity{} = activity <- Activity.normalize(ap_id), %Activity{} = activity <- Activity.normalize(ap_id),
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
conn conn

View file

@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
require Pleroma.Constants
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()} @spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do with {:ok, data, meta} <- object_action(actor, object) do
@ -120,6 +122,29 @@ defmodule Pleroma.Web.ActivityPub.Builder do
end end
end end
def announce(actor, object, options \\ []) do
public? = Keyword.get(options, :public, false)
to = [actor.follower_address, object.data["actor"]]
to =
if public? do
[Pleroma.Constants.as_public() | to]
else
to
end
{:ok,
%{
"id" => Utils.generate_activity_id(),
"actor" => actor.ap_id,
"object" => object.data["id"],
"to" => to,
"context" => object.data["context"],
"type" => "Announce",
"published" => Utils.make_date()
}, []}
end
@spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()} @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
defp object_action(actor, object) do defp object_action(actor, object) do
object_actor = User.get_cached_by_ap_id(object.data["actor"]) object_actor = User.get_cached_by_ap_id(object.data["actor"])

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
@ -84,6 +85,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end end
end end
def validate(%{"type" => "Announce"} = object, meta) do
with {:ok, object} <-
object
|> AnnounceValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object |> Map.from_struct())
{:ok, object, meta}
end
end
def cast_and_apply(%{"type" => "ChatMessage"} = object) do def cast_and_apply(%{"type" => "ChatMessage"} = object) do
ChatMessageValidator.cast_and_apply(object) ChatMessageValidator.cast_and_apply(object)
end end
@ -116,7 +127,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def fetch_actor_and_object(object) do def fetch_actor_and_object(object) do
fetch_actor(object) fetch_actor(object)
Object.normalize(object["object"]) Object.normalize(object["object"], true)
:ok :ok
end end
end end

View file

@ -0,0 +1,101 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
use Ecto.Schema
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
require Pleroma.Constants
@primary_key false
embedded_schema do
field(:id, Types.ObjectID, primary_key: true)
field(:type, :string)
field(:object, Types.ObjectID)
field(:actor, Types.ObjectID)
field(:context, :string, autogenerate: {Utils, :generate_context_id, []})
field(:to, Types.Recipients, default: [])
field(:cc, Types.Recipients, default: [])
field(:published, Types.DateTime)
end
def cast_and_validate(data) do
data
|> cast_data()
|> validate_data()
end
def cast_data(data) do
%__MODULE__{}
|> changeset(data)
end
def changeset(struct, data) do
struct
|> cast(data, __schema__(:fields))
|> fix_after_cast()
end
def fix_after_cast(cng) do
cng
end
def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["Announce"])
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|> validate_actor_presence()
|> validate_object_presence()
|> validate_existing_announce()
|> validate_announcable()
end
def validate_announcable(cng) do
with actor when is_binary(actor) <- get_field(cng, :actor),
object when is_binary(object) <- get_field(cng, :object),
%User{} = actor <- User.get_cached_by_ap_id(actor),
%Object{} = object <- Object.get_cached_by_ap_id(object),
false <- Visibility.is_public?(object) do
same_actor = object.data["actor"] == actor.ap_id
is_public = Pleroma.Constants.as_public() in (get_field(cng, :to) ++ get_field(cng, :cc))
cond do
same_actor && is_public ->
cng
|> add_error(:actor, "can not announce this object publicly")
!same_actor ->
cng
|> add_error(:actor, "can not announce this object")
true ->
cng
end
else
_ -> cng
end
end
def validate_existing_announce(cng) do
actor = get_field(cng, :actor)
object = get_field(cng, :object)
if actor && object && Utils.get_existing_announce(actor, %{data: %{"id" => object}}) do
cng
|> add_error(:actor, "already announced this object")
|> add_error(:object, "already announced by this actor")
else
cng
end
end
end

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Web.ActivityPub.Pipeline do defmodule Pleroma.Web.ActivityPub.Pipeline do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@ -44,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
defp maybe_federate(%Activity{} = activity, meta) do defp maybe_federate(%Activity{} = activity, meta) do
with {:ok, local} <- Keyword.fetch(meta, :local) do with {:ok, local} <- Keyword.fetch(meta, :local) do
do_not_federate = meta[:do_not_federate] do_not_federate = meta[:do_not_federate] || !Config.get([:instance, :federating])
if !do_not_federate && local do if !do_not_federate && local do
Federator.publish(activity) Federator.publish(activity)

View file

@ -4,9 +4,10 @@
defmodule Pleroma.Web.ActivityPub.Relay do defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
require Logger require Logger
@relay_nickname "relay" @relay_nickname "relay"
@ -48,11 +49,11 @@ defmodule Pleroma.Web.ActivityPub.Relay do
end end
end end
@spec publish(any()) :: {:ok, Activity.t(), Object.t()} | {:error, any()} @spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
def publish(%Activity{data: %{"type" => "Create"}} = activity) do def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(), with %User{} = user <- get_actor(),
%Object{} = object <- Object.normalize(activity) do true <- Visibility.is_public?(activity) do
ActivityPub.announce(user, object, nil, true, false) CommonAPI.repeat(activity.id, user)
else else
error -> format_error(error) error -> format_error(error)
end end

View file

@ -42,6 +42,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end end
end end
# Tasks this handles:
# - Add announce to object
# - Set up notification
# - Stream out the announce
def handle(%{data: %{"type" => "Announce"}} = object, meta) do
announced_object = Object.get_by_ap_id(object.data["object"])
Utils.add_announce_to_object(object, announced_object)
Notification.create_notifications(object)
ActivityPub.stream_out(object)
{:ok, object, meta}
end
def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
with undone_object <- Activity.get_by_ap_id(undone_object), with undone_object <- Activity.get_by_ap_id(undone_object),
:ok <- handle_undoing(undone_object) do :ok <- handle_undoing(undone_object) do

View file

@ -672,7 +672,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def handle_incoming(%{"type" => type} = data, _options) when type in ["Like", "EmojiReact"] do def handle_incoming(%{"type" => type} = data, _options)
when type in ["Like", "EmojiReact", "Announce"] do
with :ok <- ObjectValidator.fetch_actor_and_object(data), with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <- {:ok, activity, _meta} <-
Pipeline.common_pipeline(data, local: false) do Pipeline.common_pipeline(data, local: false) do
@ -682,21 +683,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def handle_incoming(
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
_options
) do
with actor <- Containment.get_actor(data),
{:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_embedded_obj_helper(object_id, actor),
public <- Visibility.is_public?(data),
{:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do
{:ok, activity}
else
_e -> :error
end
end
def handle_incoming( def handle_incoming(
%{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} = %{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} =
data, data,

View file

@ -98,13 +98,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["read:statuses"], admin: true} %{scopes: ["read:statuses"], admin: true}
when action in [:list_statuses, :list_user_statuses, :list_instance_statuses, :status_show] when action in [:list_user_statuses, :list_instance_statuses]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:statuses"], admin: true}
when action in [:status_update, :status_delete]
) )
plug( plug(
@ -136,7 +130,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
] ]
) )
action_fallback(:errors) action_fallback(AdminAPI.FallbackController)
def user_delete(conn, %{"nickname" => nickname}) do def user_delete(conn, %{"nickname" => nickname}) do
user_delete(conn, %{"nicknames" => [nickname]}) user_delete(conn, %{"nicknames" => [nickname]})
@ -597,16 +591,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
json_response(conn, :no_content, "") json_response(conn, :no_content, "")
else else
{:registrations_open, _} -> {:registrations_open, _} ->
errors(
conn,
{:error, "To send invites you need to set the `registrations_open` option to false."} {:error, "To send invites you need to set the `registrations_open` option to false."}
)
{:invites_enabled, _} -> {:invites_enabled, _} ->
errors(
conn,
{:error, "To send invites you need to set the `invites_enabled` option to true."} {:error, "To send invites you need to set the `invites_enabled` option to true."}
)
end end
end end
@ -814,71 +802,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
end end
def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
godmode = params["godmode"] == "true" || params["godmode"] == true
local_only = params["local_only"] == "true" || params["local_only"] == true
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
{page, page_size} = page_params(params)
activities =
ActivityPub.fetch_statuses(nil, %{
"godmode" => godmode,
"local_only" => local_only,
"limit" => page_size,
"offset" => (page - 1) * page_size,
"exclude_reblogs" => !with_reblogs && "true"
})
conn
|> put_view(AdminAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity})
end
def status_show(conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id(id) do
conn
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
else
_ -> errors(conn, {:error, :not_found})
end
end
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
params =
params
|> Map.take(["sensitive", "visibility"])
|> Map.new(fn {key, value} -> {String.to_existing_atom(key), value} end)
with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
{:ok, sensitive} = Ecto.Type.cast(:boolean, params[:sensitive])
ModerationLog.insert_log(%{
action: "status_update",
actor: admin,
subject: activity,
sensitive: sensitive,
visibility: params[:visibility]
})
conn
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
end
end
def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
ModerationLog.insert_log(%{
action: "status_delete",
actor: user,
subject_id: id
})
json(conn, %{})
end
end
def list_log(conn, params) do def list_log(conn, params) do
{page, page_size} = page_params(params) {page, page_size} = page_params(params)
@ -904,7 +827,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
def config_show(conn, %{"only_db" => true}) do def config_show(conn, %{"only_db" => true}) do
with :ok <- configurable_from_database(conn) do with :ok <- configurable_from_database() do
configs = Pleroma.Repo.all(ConfigDB) configs = Pleroma.Repo.all(ConfigDB)
conn conn
@ -914,7 +837,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
def config_show(conn, _params) do def config_show(conn, _params) do
with :ok <- configurable_from_database(conn) do with :ok <- configurable_from_database() do
configs = ConfigDB.get_all_as_keyword() configs = ConfigDB.get_all_as_keyword()
merged = merged =
@ -953,7 +876,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
def config_update(conn, %{"configs" => configs}) do def config_update(conn, %{"configs" => configs}) do
with :ok <- configurable_from_database(conn) do with :ok <- configurable_from_database() do
{_errors, results} = {_errors, results} =
configs configs
|> Enum.filter(&whitelisted_config?/1) |> Enum.filter(&whitelisted_config?/1)
@ -997,7 +920,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
def restart(conn, _params) do def restart(conn, _params) do
with :ok <- configurable_from_database(conn) do with :ok <- configurable_from_database() do
Restarter.Pleroma.restart(Config.get(:env), 50) Restarter.Pleroma.restart(Config.get(:env), 50)
json(conn, %{}) json(conn, %{})
@ -1008,14 +931,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()}) json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
end end
defp configurable_from_database(conn) do defp configurable_from_database do
if Config.get(:configurable_from_database) do if Config.get(:configurable_from_database) do
:ok :ok
else else
errors(
conn,
{:error, "To use this endpoint you need to enable configuration from database."} {:error, "To use this endpoint you need to enable configuration from database."}
)
end end
end end
@ -1159,30 +1079,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> json(%{"status_visibility" => count}) |> json(%{"status_visibility" => count})
end end
defp errors(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> json(dgettext("errors", "Not found"))
end
defp errors(conn, {:error, reason}) do
conn
|> put_status(:bad_request)
|> json(reason)
end
defp errors(conn, {:param_cast, _}) do
conn
|> put_status(:bad_request)
|> json(dgettext("errors", "Invalid parameters"))
end
defp errors(conn, _) do
conn
|> put_status(:internal_server_error)
|> json(dgettext("errors", "Something went wrong"))
end
defp page_params(params) do defp page_params(params) do
{get_page(params["page"]), get_page_size(params["page_size"])} {get_page(params["page"]), get_page_size(params["page_size"])}
end end

View file

@ -0,0 +1,31 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.FallbackController do
use Pleroma.Web, :controller
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> json(%{error: dgettext("errors", "Not found")})
end
def call(conn, {:error, reason}) do
conn
|> put_status(:bad_request)
|> json(%{error: reason})
end
def call(conn, {:param_cast, _}) do
conn
|> put_status(:bad_request)
|> json(dgettext("errors", "Invalid parameters"))
end
def call(conn, _) do
conn
|> put_status(:internal_server_error)
|> json(%{error: dgettext("errors", "Something went wrong")})
end
end

View file

@ -0,0 +1,79 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.StatusController do
use Pleroma.Web, :controller
alias Pleroma.Activity
alias Pleroma.ModerationLog
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI
require Logger
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read:statuses"], admin: true} when action in [:index, :show])
plug(
OAuthScopesPlug,
%{scopes: ["write:statuses"], admin: true} when action in [:update, :delete]
)
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.StatusOperation
def index(%{assigns: %{user: _admin}} = conn, params) do
activities =
ActivityPub.fetch_statuses(nil, %{
"godmode" => params.godmode,
"local_only" => params.local_only,
"limit" => params.page_size,
"offset" => (params.page - 1) * params.page_size,
"exclude_reblogs" => not params.with_reblogs
})
render(conn, "index.json", activities: activities, as: :activity)
end
def show(conn, %{id: id}) do
with %Activity{} = activity <- Activity.get_by_id(id) do
conn
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
else
nil -> {:error, :not_found}
end
end
def update(%{assigns: %{user: admin}, body_params: params} = conn, %{id: id}) do
with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
ModerationLog.insert_log(%{
action: "status_update",
actor: admin,
subject: activity,
sensitive: params[:sensitive],
visibility: params[:visibility]
})
conn
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
end
end
def delete(%{assigns: %{user: user}} = conn, %{id: id}) do
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
ModerationLog.insert_log(%{
action: "status_delete",
actor: user,
subject_id: id
})
json(conn, %{})
end
end
end

View file

@ -0,0 +1,165 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.Status
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
import Pleroma.Web.ApiSpec.Helpers
import Pleroma.Web.ApiSpec.StatusOperation, only: [id_param: 0]
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def index_operation do
%Operation{
tags: ["Admin", "Statuses"],
operationId: "AdminAPI.StatusController.index",
security: [%{"oAuth" => ["read:statuses"]}],
parameters: [
Operation.parameter(
:godmode,
:query,
%Schema{type: :boolean, default: false},
"Allows to see private statuses"
),
Operation.parameter(
:local_only,
:query,
%Schema{type: :boolean, default: false},
"Excludes remote statuses"
),
Operation.parameter(
:with_reblogs,
:query,
%Schema{type: :boolean, default: false},
"Allows to see reblogs"
),
Operation.parameter(
:page,
:query,
%Schema{type: :integer, default: 1},
"Page"
),
Operation.parameter(
:page_size,
:query,
%Schema{type: :integer, default: 50},
"Number of statuses to return"
)
],
responses: %{
200 =>
Operation.response("Array of statuses", "application/json", %Schema{
type: :array,
items: status()
})
}
}
end
def show_operation do
%Operation{
tags: ["Admin", "Statuses"],
summary: "Show Status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param()],
security: [%{"oAuth" => ["read:statuses"]}],
responses: %{
200 => Operation.response("Status", "application/json", Status),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def update_operation do
%Operation{
tags: ["Admin", "Statuses"],
summary: "Change the scope of an individual reported status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param()],
security: [%{"oAuth" => ["write:statuses"]}],
requestBody: request_body("Parameters", update_request(), required: true),
responses: %{
200 => Operation.response("Status", "application/json", Status),
400 => Operation.response("Error", "application/json", ApiError)
}
}
end
def delete_operation do
%Operation{
tags: ["Admin", "Statuses"],
summary: "Delete an individual reported status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param()],
security: [%{"oAuth" => ["write:statuses"]}],
responses: %{
200 => empty_object_response(),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
defp status do
%Schema{
anyOf: [
Status,
%Schema{
type: :object,
properties: %{
account: %Schema{allOf: [Account, admin_account()]}
}
}
]
}
end
defp admin_account do
%Schema{
type: :object,
properties: %{
id: FlakeID,
avatar: %Schema{type: :string},
nickname: %Schema{type: :string},
display_name: %Schema{type: :string},
deactivated: %Schema{type: :boolean},
local: %Schema{type: :boolean},
roles: %Schema{
type: :object,
properties: %{
admin: %Schema{type: :boolean},
moderator: %Schema{type: :boolean}
}
},
tags: %Schema{type: :string},
confirmation_pending: %Schema{type: :string}
}
}
end
defp update_request do
%Schema{
type: :object,
properties: %{
sensitive: %Schema{
type: :boolean,
description: "Mark status and attached media as sensitive?"
},
visibility: VisibilityScope
},
example: %{
"visibility" => "private",
"sensitive" => "false"
}
}
end
end

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
alias OpenApiSpex.Operation alias OpenApiSpex.Operation
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.Status alias Pleroma.Web.ApiSpec.Schemas.Status
@ -46,7 +47,8 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
security: [%{"oAuth" => ["write:statuses"]}], security: [%{"oAuth" => ["write:statuses"]}],
operationId: "EmojiReactionController.create", operationId: "EmojiReactionController.create",
responses: %{ responses: %{
200 => Operation.response("Status", "application/json", Status) 200 => Operation.response("Status", "application/json", Status),
400 => Operation.response("Bad Request", "application/json", ApiError)
} }
} }
end end

View file

@ -8,6 +8,8 @@ defmodule Pleroma.Web.ApiSpec.PleromaNotificationOperation do
alias Pleroma.Web.ApiSpec.NotificationOperation alias Pleroma.Web.ApiSpec.NotificationOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
import Pleroma.Web.ApiSpec.Helpers
def open_api_operation(action) do def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation") operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, []) apply(__MODULE__, operation, [])
@ -17,10 +19,14 @@ defmodule Pleroma.Web.ApiSpec.PleromaNotificationOperation do
%Operation{ %Operation{
tags: ["Notifications"], tags: ["Notifications"],
summary: "Mark notifications as read. Query parameters are mutually exclusive.", summary: "Mark notifications as read. Query parameters are mutually exclusive.",
parameters: [ requestBody:
Operation.parameter(:id, :query, :string, "A single notification ID to read"), request_body("Parameters", %Schema{
Operation.parameter(:max_id, :query, :string, "Read all notifications up to this id") type: :object,
], properties: %{
id: %Schema{type: :integer, description: "A single notification ID to read"},
max_id: %Schema{type: :integer, description: "Read all notifications up to this ID"}
}
}),
security: [%{"oAuth" => ["write:notifications"]}], security: [%{"oAuth" => ["write:notifications"]}],
operationId: "PleromaAPI.NotificationController.mark_as_read", operationId: "PleromaAPI.NotificationController.mark_as_read",
responses: %{ responses: %{

View file

@ -487,7 +487,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
} }
end end
defp id_param do def id_param do
Operation.parameter(:id, :path, FlakeID, "Status ID", Operation.parameter(:id, :path, FlakeID, "Status ID",
example: "9umDrYheeY451cQnEe", example: "9umDrYheeY451cQnEe",
required: true required: true

View file

@ -167,18 +167,19 @@ defmodule Pleroma.Web.CommonAPI do
end end
def repeat(id, user, params \\ %{}) do def repeat(id, user, params \\ %{}) do
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id) do with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
object = Object.normalize(activity) object = %Object{} <- Object.normalize(activity, false),
announce_activity = Utils.get_existing_announce(user.ap_id, object) {_, nil} <- {:existing_announce, Utils.get_existing_announce(user.ap_id, object)},
public = public_announce?(object, params) public = public_announce?(object, params),
{:ok, announce, _} <- Builder.announce(user, object, public: public),
{:ok, activity, _} <- Pipeline.common_pipeline(announce, local: true) do
{:ok, activity}
else
{:existing_announce, %Activity{} = announce} ->
{:ok, announce}
if announce_activity do _ ->
{:ok, announce_activity, object} {:error, :not_found}
else
ActivityPub.announce(user, object, nil, true, public)
end
else
_ -> {:error, :not_found}
end end
end end

View file

@ -102,7 +102,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end end
def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct", _) do def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct", _) do
if inReplyTo do # If the OP is a DM already, add the implicit actor.
if inReplyTo && Visibility.is_direct?(inReplyTo) do
{Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []} {Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
else else
{mentioned_users, []} {mentioned_users, []}
@ -395,10 +396,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def to_masto_date(_), do: "" def to_masto_date(_), do: ""
defp shortname(name) do defp shortname(name) do
if String.length(name) < 30 do with max_length when max_length > 0 <-
name Config.get([Pleroma.Upload, :filename_display_max_length], 30),
true <- String.length(name) > max_length do
String.slice(name, 0..max_length) <> ""
else else
String.slice(name, 0..30) <> "" _ -> name
end end
end end
@ -467,6 +470,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)
recipients ++ subscriber_ids recipients ++ subscriber_ids
else
_e -> recipients
end end
end end
@ -478,6 +483,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|> User.get_followers() |> User.get_followers()
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)
|> Enum.concat(recipients) |> Enum.concat(recipients)
else
_e -> recipients
end end
end end

View file

@ -210,7 +210,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
@doc "POST /api/v1/statuses/:id/reblog" @doc "POST /api/v1/statuses/:id/reblog"
def reblog(%{assigns: %{user: user}, body_params: params} = conn, %{id: ap_id_or_id}) do def reblog(%{assigns: %{user: user}, body_params: params} = conn, %{id: ap_id_or_id}) do
with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user, params), with {:ok, announce} <- CommonAPI.repeat(ap_id_or_id, user, params),
%Activity{} = announce <- Activity.normalize(announce.data) do %Activity{} = announce <- Activity.normalize(announce.data) do
try_render(conn, "show.json", %{activity: announce, for: user, as: :activity}) try_render(conn, "show.json", %{activity: announce, for: user, as: :activity})
end end

View file

@ -23,7 +23,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
streaming_api: Pleroma.Web.Endpoint.websocket_url() streaming_api: Pleroma.Web.Endpoint.websocket_url()
}, },
stats: Pleroma.Stats.get_stats(), stats: Pleroma.Stats.get_stats(),
thumbnail: Pleroma.Web.base_url() <> "/instance/thumbnail.jpeg", thumbnail: instance_thumbnail(),
languages: ["en"], languages: ["en"],
registrations: Keyword.get(instance, :registrations_open), registrations: Keyword.get(instance, :registrations_open),
# Extra (not present in Mastodon): # Extra (not present in Mastodon):
@ -88,4 +88,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
end end
|> Map.put(:enabled, Config.get([:instance, :federating])) |> Map.put(:enabled, Config.get([:instance, :federating]))
end end
defp instance_thumbnail do
Pleroma.Config.get([:instance, :instance_thumbnail]) ||
"#{Pleroma.Web.base_url()}/instance/thumbnail.jpeg"
end
end end

View file

@ -32,13 +32,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
action_fallback(:errors) action_fallback(:errors)
def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) def object(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :object) ActivityPubController.call(conn, :object)
end end
def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do def object(%{assigns: %{format: format}} = conn, _params) do
with id <- o_status_url(conn, :object, uuid), with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
@ -54,13 +54,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end end
end end
def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid}) def activity(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :activity) ActivityPubController.call(conn, :activity)
end end
def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do def activity(%{assigns: %{format: format}} = conn, _params) do
with id <- o_status_url(conn, :activity, uuid), with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do {_, true} <- {:public?, Visibility.is_public?(activity)} do
case format do case format do

View file

@ -22,6 +22,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.EmojiReactionOperation defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.EmojiReactionOperation
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
%Object{data: %{"reactions" => reactions}} when is_list(reactions) <- %Object{data: %{"reactions" => reactions}} when is_list(reactions) <-

View file

@ -14,7 +14,7 @@ defmodule Pleroma.Web.PleromaAPI.NotificationController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation
def mark_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do def mark_as_read(%{assigns: %{user: user}, body_params: %{id: notification_id}} = conn, _) do
with {:ok, notification} <- Notification.read_one(user, notification_id) do with {:ok, notification} <- Notification.read_one(user, notification_id) do
render(conn, "show.json", notification: notification, for: user) render(conn, "show.json", notification: notification, for: user)
else else
@ -25,7 +25,7 @@ defmodule Pleroma.Web.PleromaAPI.NotificationController do
end end
end end
def mark_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do def mark_as_read(%{assigns: %{user: user}, body_params: %{max_id: max_id}} = conn, _) do
notifications = notifications =
user user
|> Notification.set_read_up_to(max_id) |> Notification.set_read_up_to(max_id)

View file

@ -189,10 +189,10 @@ defmodule Pleroma.Web.Router do
post("/reports/:id/notes", AdminAPIController, :report_notes_create) post("/reports/:id/notes", AdminAPIController, :report_notes_create)
delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete) delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete)
get("/statuses/:id", AdminAPIController, :status_show) get("/statuses/:id", StatusController, :show)
put("/statuses/:id", AdminAPIController, :status_update) put("/statuses/:id", StatusController, :update)
delete("/statuses/:id", AdminAPIController, :status_delete) delete("/statuses/:id", StatusController, :delete)
get("/statuses", AdminAPIController, :list_statuses) get("/statuses", StatusController, :index)
get("/config", AdminAPIController, :config_show) get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update) post("/config", AdminAPIController, :config_update)
@ -564,6 +564,10 @@ defmodule Pleroma.Web.Router do
get("/notice/:id", OStatus.OStatusController, :notice) get("/notice/:id", OStatus.OStatusController, :notice)
get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player)
# Mastodon compatibility routes
get("/users/:nickname/statuses/:id", OStatus.OStatusController, :object)
get("/users/:nickname/statuses/:id/activity", OStatus.OStatusController, :activity)
get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)
get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed) get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed)

View file

@ -0,0 +1 @@
If you are an instance admin and you want to modify the instace static files, this is probably not the right place to do it. This directory is checked in version control, so don't be surprised if you get merge conflicts after modifying anything here. Please use instance static directory instead, it has the same directory structure and files placed there will override files placed here. See https://docs.pleroma.social/backend/configuration/static_dir/ for more info

View file

@ -1 +1,88 @@
{"@context":["https://www.w3.org/ns/activitystreams","https://puckipedia.com/-/context"],"actor":{"endpoints":"https://puckipedia.com/#endpoints","followers":"https://puckipedia.com/followers","following":"https://puckipedia.com/following","icon":{"mediaType":"image/png","type":"Image","url":"https://puckipedia.com/images/avatar.png"},"id":"https://puckipedia.com/","inbox":"https://puckipedia.com/inbox","kroeg:blocks":{"id":"https://puckipedia.com/blocks"},"liked":"https://puckipedia.com/liked","manuallyApprovesFollowers":false,"name":"HACKER TEEN PUCKIPEDIA 👩‍💻","outbox":"https://puckipedia.com/outbox","preferredUsername":"puckipedia","publicKey":{"id":"https://puckipedia.com/#key","owner":"https://puckipedia.com/","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----","type":[]},"summary":"<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>","type":"Person","updated":"2017-12-19T16:56:29.7576707+00:00"},"cc":"http://mastodon.example.org/users/admin","id":"https://puckipedia.com/cc56a9658e","object":{"as:sensitive":false,"attributedTo":{"endpoints":{"sharedInbox":"https://mastodon.social/inbox","type":[]},"followers":"http://mastodon.example.org/users/admin/followers","following":"http://mastodon.example.org/users/admin/following","icon":{"mediaType":"image/png","type":"Image","url":"https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"},"id":"http://mastodon.example.org/users/admin","inbox":"http://mastodon.example.org/users/admin/inbox","manuallyApprovesFollowers":{"@value":"False","type":"xsd:boolean"},"name":"","outbox":"http://mastodon.example.org/users/admin/outbox","preferredUsername":"revenant","publicKey":{"id":"http://mastodon.example.org/users/admin#main-key","owner":"http://mastodon.example.org/users/admin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n","type":[]},"summary":"<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>","type":"Person","url":"https://mastodon.social/@revenant"},"cc":"http://mastodon.example.org/users/admin/followers","content":"<p>the name&apos;s jond (jeans bond)</p>","contentMap":{"en":"<p>the name&apos;s jond (jeans bond)</p>"},"conversation":"tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation","id":"http://mastodon.example.org/users/admin/statuses/100787282858396771","ostatus:atomUri":"http://mastodon.example.org/users/admin/statuses/100787282858396771","published":"2018-09-25T16:11:29Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"https://mastodon.social/@revenant/100787282858396771"},"to":["https://www.w3.org/ns/activitystreams#Public","https://puckipedia.com/followers"],"type":"Announce"} {
"@context" : [
"https://www.w3.org/ns/activitystreams",
"https://puckipedia.com/-/context"
],
"actor" : {
"endpoints" : "https://puckipedia.com/#endpoints",
"followers" : "https://puckipedia.com/followers",
"following" : "https://puckipedia.com/following",
"icon" : {
"mediaType" : "image/png",
"type" : "Image",
"url" : "https://puckipedia.com/images/avatar.png"
},
"id" : "https://puckipedia.com/",
"inbox" : "https://puckipedia.com/inbox",
"kroeg:blocks" : {
"id" : "https://puckipedia.com/blocks"
},
"liked" : "https://puckipedia.com/liked",
"manuallyApprovesFollowers" : false,
"name" : "HACKER TEEN PUCKIPEDIA 👩‍💻",
"outbox" : "https://puckipedia.com/outbox",
"preferredUsername" : "puckipedia",
"publicKey" : {
"id" : "https://puckipedia.com/#key",
"owner" : "https://puckipedia.com/",
"publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----",
"type" : []
},
"summary" : "<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>",
"type" : "Person",
"updated" : "2017-12-19T16:56:29.7576707+00:00"
},
"cc" : "http://mastodon.example.org/users/admin",
"id" : "https://puckipedia.com/cc56a9658e",
"object" : {
"as:sensitive" : false,
"attributedTo" : {
"endpoints" : {
"sharedInbox" : "https://mastodon.social/inbox",
"type" : []
},
"followers" : "http://mastodon.example.org/users/admin/followers",
"following" : "http://mastodon.example.org/users/admin/following",
"icon" : {
"mediaType" : "image/png",
"type" : "Image",
"url" : "https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"
},
"id" : "http://mastodon.example.org/users/admin",
"inbox" : "http://mastodon.example.org/users/admin/inbox",
"manuallyApprovesFollowers" : {
"@value" : "False",
"type" : "xsd:boolean"
},
"name" : "",
"outbox" : "http://mastodon.example.org/users/admin/outbox",
"preferredUsername" : "revenant",
"publicKey" : {
"id" : "http://mastodon.example.org/users/admin#main-key",
"owner" : "http://mastodon.example.org/users/admin",
"publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n",
"type" : []
},
"summary" : "<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>",
"type" : "Person",
"url" : "https://mastodon.social/@revenant"
},
"cc" : "http://mastodon.example.org/users/admin/followers",
"content" : "<p>the name&apos;s jond (jeans bond)</p>",
"contentMap" : {
"en" : "<p>the name&apos;s jond (jeans bond)</p>"
},
"conversation" : "tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation",
"id" : "http://mastodon.example.org/users/admin/statuses/100787282858396771",
"ostatus:atomUri" : "http://mastodon.example.org/users/admin/statuses/100787282858396771",
"published" : "2018-09-25T16:11:29Z",
"to" : "https://www.w3.org/ns/activitystreams#Public",
"type" : "Note",
"url" : "https://mastodon.social/@revenant/100787282858396771"
},
"to" : [
"https://www.w3.org/ns/activitystreams#Public",
"https://puckipedia.com/followers"
],
"type" : "Announce"
}

View file

@ -1,9 +1,45 @@
{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":"as:movedTo","Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji"}],"id":"http://mastodon.example.org/users/admin/statuses/99541947525187367","type":"Note","summary":null,"content":"\u003cp\u003eyeah.\u003c/p\u003e","inReplyTo":null,"published":"2018-02-17T17:46:20Z","url":"http://mastodon.example.org/@admin/99541947525187367","attributedTo":"http://mastodon.example.org/users/admin","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["http://mastodon.example.org/users/admin/followers"],"sensitive":false,"atomUri":"http://mastodon.example.org/users/admin/statuses/99541947525187367","inReplyToAtomUri":null,"conversation":"tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation","tag":[], {
"@context" : [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"Emoji" : "toot:Emoji",
"Hashtag" : "as:Hashtag",
"atomUri" : "ostatus:atomUri",
"conversation" : "ostatus:conversation",
"inReplyToAtomUri" : "ostatus:inReplyToAtomUri",
"manuallyApprovesFollowers" : "as:manuallyApprovesFollowers",
"movedTo" : "as:movedTo",
"ostatus" : "http://ostatus.org#",
"sensitive" : "as:sensitive",
"toot" : "http://joinmastodon.org/ns#"
}
],
"atomUri" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
"attachment" : [ "attachment" : [
{ {
"url": "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", "mediaType" : "image/jpeg",
"type": "Document",
"name" : null, "name" : null,
"mediaType": "image/jpeg" "type" : "Document",
"url" : "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg"
}
],
"attributedTo" : "http://mastodon.example.org/users/admin",
"cc" : [
"http://mastodon.example.org/users/admin/followers"
],
"content" : "<p>yeah.</p>",
"conversation" : "tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation",
"id" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
"inReplyTo" : null,
"inReplyToAtomUri" : null,
"published" : "2018-02-17T17:46:20Z",
"sensitive" : false,
"summary" : null,
"tag" : [],
"to" : [
"https://www.w3.org/ns/activitystreams#Public"
],
"type" : "Note",
"url" : "http://mastodon.example.org/@admin/99541947525187367"
} }
]}

View file

@ -648,7 +648,7 @@ defmodule Pleroma.NotificationTest do
status: "hey @#{other_user.nickname}!" status: "hey @#{other_user.nickname}!"
}) })
{:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user) {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
{enabled_receivers, _disabled_receivers} = {enabled_receivers, _disabled_receivers} =
Notification.get_notified_from_activity(activity_two) Notification.get_notified_from_activity(activity_two)
@ -778,7 +778,7 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user)) assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1 assert length(Notification.for_user(user)) == 1
@ -795,7 +795,7 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user)) assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1 assert length(Notification.for_user(user)) == 1

View file

@ -63,7 +63,7 @@ defmodule Pleroma.InstanceTest do
"--uploads-dir", "--uploads-dir",
"test/uploads", "test/uploads",
"--static-dir", "--static-dir",
"instance/static/" "./test/../test/instance/static/"
]) ])
end end
@ -83,6 +83,7 @@ defmodule Pleroma.InstanceTest do
assert generated_config =~ "configurable_from_database: true" assert generated_config =~ "configurable_from_database: true"
assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]" assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]"
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
end end
defp generated_setup_psql do defp generated_setup_psql do

View file

@ -91,6 +91,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
describe "running rm" do describe "running rm" do
test "user is deleted" do test "user is deleted" do
clear_config([:instance, :federating], true)
user = insert(:user) user = insert(:user)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
@ -108,8 +109,10 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "a remote user's create activity is deleted when the object has been pruned" do test "a remote user's create activity is deleted when the object has been pruned" do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "uguu"}) {:ok, post} = CommonAPI.post(user, %{status: "uguu"})
clear_config([:instance, :federating], true)
object = Object.normalize(post) object = Object.normalize(post)
Object.prune(object) Object.prune(object)

View file

@ -992,7 +992,7 @@ defmodule Pleroma.UserTest do
user = insert(:user, local: true) user = insert(:user, local: true)
{:ok, activity} = CommonAPI.post(actor, %{status: "hello"}) {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user) {:ok, announce} = CommonAPI.repeat(activity.id, user)
recipients = User.get_recipients_from_activity(announce) recipients = User.get_recipients_from_activity(announce)
@ -1147,7 +1147,7 @@ defmodule Pleroma.UserTest do
{:ok, like} = CommonAPI.favorite(user, activity_two.id) {:ok, like} = CommonAPI.favorite(user, activity_two.id)
{:ok, like_two} = CommonAPI.favorite(follower, activity.id) {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
{:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user) {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
{:ok, job} = User.delete(user) {:ok, job} = User.delete(user)
{:ok, _user} = ObanHelpers.perform(job) {:ok, _user} = ObanHelpers.perform(job)
@ -1777,4 +1777,16 @@ defmodule Pleroma.UserTest do
assert result.email_notifications["digest"] == false assert result.email_notifications["digest"] == false
end end
end end
test "avatar fallback" do
user = insert(:user)
assert User.avatar_url(user) =~ "/images/avi.png"
Pleroma.Config.put([:assets, :default_user_avatar], "avatar.png")
user = User.get_cached_by_nickname_or_id(user.nickname)
assert User.avatar_url(user) =~ "avatar.png"
assert User.avatar_url(user, no_default: true) == nil
end
end end

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
use Pleroma.Web.ConnCase use Pleroma.Web.ConnCase
use Oban.Testing, repo: Pleroma.Repo use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Delivery alias Pleroma.Delivery
@ -14,13 +13,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers alias Pleroma.Tests.ObanHelpers
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
alias Pleroma.Workers.ReceiverWorker alias Pleroma.Workers.ReceiverWorker
import Pleroma.Factory
require Pleroma.Constants
setup_all do setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok :ok
@ -168,6 +173,60 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end end
end end
describe "mastodon compatibility routes" do
test "it returns a json representation of the object with accept application/json", %{
conn: conn
} do
{:ok, object} =
%{
"type" => "Note",
"content" => "hey",
"id" => Endpoint.url() <> "/users/raymoo/statuses/999999999",
"actor" => Endpoint.url() <> "/users/raymoo",
"to" => [Pleroma.Constants.as_public()]
}
|> Object.create()
conn =
conn
|> put_req_header("accept", "application/json")
|> get("/users/raymoo/statuses/999999999")
assert json_response(conn, 200) == ObjectView.render("object.json", %{object: object})
end
test "it returns a json representation of the activity with accept application/json", %{
conn: conn
} do
{:ok, object} =
%{
"type" => "Note",
"content" => "hey",
"id" => Endpoint.url() <> "/users/raymoo/statuses/999999999",
"actor" => Endpoint.url() <> "/users/raymoo",
"to" => [Pleroma.Constants.as_public()]
}
|> Object.create()
{:ok, activity, _} =
%{
"id" => object.data["id"] <> "/activity",
"type" => "Create",
"object" => object.data["id"],
"actor" => object.data["actor"],
"to" => object.data["to"]
}
|> ActivityPub.persist(local: true)
conn =
conn
|> put_req_header("accept", "application/json")
|> get("/users/raymoo/statuses/999999999/activity")
assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity})
end
end
describe "/objects/:uuid" do describe "/objects/:uuid" do
test "it returns a json representation of the object with accept application/json", %{ test "it returns a json representation of the object with accept application/json", %{
conn: conn conn: conn

View file

@ -537,7 +537,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)
{:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]}) {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Activity.get_by_id(activity_three.id) activity_three = Activity.get_by_id(activity_three.id)
@ -592,7 +592,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
{:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend) {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
@ -618,7 +618,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
followed_user = insert(:user) followed_user = insert(:user)
ActivityPub.follow(user, followed_user) ActivityPub.follow(user, followed_user)
{:ok, repeat_activity, _} = CommonAPI.repeat(activity.id, followed_user) {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@ -651,7 +651,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"}) another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})
bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}}) bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})
bad_activity = insert(:note_activity, %{note: bad_note}) bad_activity = insert(:note_activity, %{note: bad_note})
{:ok, repeat_activity, _} = CommonAPI.repeat(bad_activity.id, domain_user) {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
@ -699,7 +699,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_three_actor = User.get_by_ap_id(activity_three.data["actor"]) activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
{:ok, _user_relationships} = User.mute(user, activity_three_actor) {:ok, _user_relationships} = User.mute(user, activity_three_actor)
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Activity.get_by_id(activity_three.id) activity_three = Activity.get_by_id(activity_three.id)
@ -749,7 +749,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = User.follow(user, booster) {:ok, user} = User.follow(user, booster)
{:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster) {:ok, announce} = CommonAPI.repeat(activity_three.id, booster)
[announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)]) [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
@ -846,7 +846,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
booster = insert(:user) booster = insert(:user)
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster) {:ok, activity} = CommonAPI.repeat(activity.id, booster)
activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
@ -860,7 +860,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster) {:ok, activity} = CommonAPI.repeat(activity.id, booster)
activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
@ -868,75 +868,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end end
end end
describe "announcing an object" do
test "adds an announce activity to the db" do
note_activity = insert(:note_activity)
object = Object.normalize(note_activity)
user = insert(:user)
{:ok, announce_activity, object} = ActivityPub.announce(user, object)
assert object.data["announcement_count"] == 1
assert object.data["announcements"] == [user.ap_id]
assert announce_activity.data["to"] == [
User.ap_followers(user),
note_activity.data["actor"]
]
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
test "reverts annouce from object on error" do
note_activity = insert(:note_activity)
object = Object.normalize(note_activity)
user = insert(:user)
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
assert {:error, :reverted} = ActivityPub.announce(user, object)
end
reloaded_object = Object.get_by_ap_id(object.data["id"])
assert reloaded_object == object
refute reloaded_object.data["announcement_count"]
refute reloaded_object.data["announcements"]
end
end
describe "announcing a private object" do
test "adds an announce activity to the db if the audience is not widened" do
user = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
{:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
assert announce_activity.data["to"] == [User.ap_followers(user)]
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
test "does not add an announce activity to the db if the audience is widened" do
user = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
end
test "does not add an announce activity to the db if the announcer is not the author" do
user = insert(:user)
announcer = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
end
end
describe "uploading files" do describe "uploading files" do
test "copies the file to the configured folder" do test "copies the file to the configured folder" do
file = %Plug.Upload{ file = %Plug.Upload{

View file

@ -516,4 +516,96 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
assert {:object, valid_like["object"]} in validated.changes assert {:object, valid_like["object"]} in validated.changes
end end
end end
describe "announces" do
setup do
user = insert(:user)
announcer = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
object = Object.normalize(post_activity, false)
{:ok, valid_announce, []} = Builder.announce(announcer, object)
%{
valid_announce: valid_announce,
user: user,
post_activity: post_activity,
announcer: announcer
}
end
test "returns ok for a valid announce", %{valid_announce: valid_announce} do
assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, [])
end
test "returns an error if the object can't be found", %{valid_announce: valid_announce} do
without_object =
valid_announce
|> Map.delete("object")
{:error, cng} = ObjectValidator.validate(without_object, [])
assert {:object, {"can't be blank", [validation: :required]}} in cng.errors
nonexisting_object =
valid_announce
|> Map.put("object", "https://gensokyo.2hu/objects/99999999")
{:error, cng} = ObjectValidator.validate(nonexisting_object, [])
assert {:object, {"can't find object", []}} in cng.errors
end
test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do
nonexisting_actor =
valid_announce
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
{:error, cng} = ObjectValidator.validate(nonexisting_actor, [])
assert {:actor, {"can't find user", []}} in cng.errors
end
test "returns an error if the actor already announced the object", %{
valid_announce: valid_announce,
announcer: announcer,
post_activity: post_activity
} do
_announce = CommonAPI.repeat(post_activity.id, announcer)
{:error, cng} = ObjectValidator.validate(valid_announce, [])
assert {:actor, {"already announced this object", []}} in cng.errors
assert {:object, {"already announced by this actor", []}} in cng.errors
end
test "returns an error if the actor can't announce the object", %{
announcer: announcer,
user: user
} do
{:ok, post_activity} =
CommonAPI.post(user, %{status: "a secret post", visibility: "private"})
object = Object.normalize(post_activity, false)
# Another user can't announce it
{:ok, announce, []} = Builder.announce(announcer, object, public: false)
{:error, cng} = ObjectValidator.validate(announce, [])
assert {:actor, {"can not announce this object", []}} in cng.errors
# The actor of the object can announce it
{:ok, announce, []} = Builder.announce(user, object, public: false)
assert {:ok, _, _} = ObjectValidator.validate(announce, [])
# The actor of the object can not announce it publicly
{:ok, announce, []} = Builder.announce(user, object, public: true)
{:error, cng} = ObjectValidator.validate(announce, [])
assert {:actor, {"can not announce this object publicly", []}} in cng.errors
end
end
end end

View file

@ -9,6 +9,11 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do
import Pleroma.Factory import Pleroma.Factory
describe "common_pipeline/2" do describe "common_pipeline/2" do
setup do
clear_config([:instance, :federating], true)
:ok
end
test "it goes through validation, filtering, persisting, side effects and federation for local activities" do test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
activity = insert(:note_activity) activity = insert(:note_activity)
meta = [local: true] meta = [local: true]
@ -83,5 +88,44 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end end
end end
test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do
clear_config([:instance, :federating], false)
activity = insert(:note_activity)
meta = [local: true]
with_mocks([
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
{
Pleroma.Web.ActivityPub.MRF,
[],
[filter: fn o -> {:ok, o} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
[],
[persist: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.SideEffects,
[],
[handle: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.Federator,
[],
[]
}
]) do
assert {:ok, ^activity, ^meta} =
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end
end
end end
end end

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
@ -95,21 +94,20 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
end) end)
assert capture_log(fn -> assert capture_log(fn ->
assert Relay.publish(activity) == {:error, nil} assert Relay.publish(activity) == {:error, false}
end) =~ "[error] error: nil" end) =~ "[error] error: false"
end end
test_with_mock "returns announce activity and publish to federate", test_with_mock "returns announce activity and publish to federate",
Pleroma.Web.Federator, Pleroma.Web.Federator,
[:passthrough], [:passthrough],
[] do [] do
Pleroma.Config.put([:instance, :federating], true) clear_config([:instance, :federating], true)
service_actor = Relay.get_actor() service_actor = Relay.get_actor()
note = insert(:note_activity) note = insert(:note_activity)
assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) assert {:ok, %Activity{} = activity} = Relay.publish(note)
assert activity.data["type"] == "Announce" assert activity.data["type"] == "Announce"
assert activity.data["actor"] == service_actor.ap_id assert activity.data["actor"] == service_actor.ap_id
assert activity.data["object"] == obj.data["id"]
assert called(Pleroma.Web.Federator.publish(activity)) assert called(Pleroma.Web.Federator.publish(activity))
end end
@ -117,13 +115,12 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
Pleroma.Web.Federator, Pleroma.Web.Federator,
[:passthrough], [:passthrough],
[] do [] do
Pleroma.Config.put([:instance, :federating], false) clear_config([:instance, :federating], false)
service_actor = Relay.get_actor() service_actor = Relay.get_actor()
note = insert(:note_activity) note = insert(:note_activity)
assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) assert {:ok, %Activity{} = activity} = Relay.publish(note)
assert activity.data["type"] == "Announce" assert activity.data["type"] == "Announce"
assert activity.data["actor"] == service_actor.ap_id assert activity.data["actor"] == service_actor.ap_id
assert activity.data["object"] == obj.data["id"]
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end

View file

@ -173,7 +173,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
{:ok, post} = CommonAPI.post(poster, %{status: "hey"}) {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, like} = CommonAPI.favorite(user, post.id) {:ok, like} = CommonAPI.favorite(user, post.id)
{:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍") {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
{:ok, announce, _} = CommonAPI.repeat(post.id, user) {:ok, announce} = CommonAPI.repeat(post.id, user)
{:ok, block} = ActivityPub.block(user, poster) {:ok, block} = ActivityPub.block(user, poster)
User.block(user, poster) User.block(user, poster)
@ -376,4 +376,61 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
assert chat assert chat
end end
end end
describe "announce objects" do
setup do
poster = insert(:user)
user = insert(:user)
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
{:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
{:ok, private_announce_data, _meta} =
Builder.announce(user, private_post.object, public: false)
{:ok, relay_announce_data, _meta} =
Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
{:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
{:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
{:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
%{
announce: announce,
user: user,
poster: poster,
private_announce: private_announce,
relay_announce: relay_announce
}
end
test "adds the announce to the original object", %{announce: announce, user: user} do
{:ok, announce, _} = SideEffects.handle(announce)
object = Object.get_by_ap_id(announce.data["object"])
assert object.data["announcement_count"] == 1
assert user.ap_id in object.data["announcements"]
end
test "does not add the announce to the original object if the actor is a service actor", %{
relay_announce: announce
} do
{:ok, announce, _} = SideEffects.handle(announce)
object = Object.get_by_ap_id(announce.data["object"])
assert object.data["announcement_count"] == nil
end
test "creates a notification", %{announce: announce, poster: poster} do
{:ok, announce, _} = SideEffects.handle(announce)
assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
end
test "it streams out the announce", %{announce: announce} do
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do
{:ok, announce, _} = SideEffects.handle(announce)
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce))
end
end
end
end end

View file

@ -0,0 +1,172 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "it works for incoming honk announces" do
user = insert(:user, ap_id: "https://honktest/u/test", local: false)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
announce = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"actor" => "https://honktest/u/test",
"id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
"object" => post.data["object"],
"published" => "2019-06-25T19:33:58Z",
"to" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Announce"
}
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
object = Object.get_by_ap_id(post.data["object"])
assert length(object.data["announcements"]) == 1
assert user.ap_id in object.data["announcements"]
end
test "it works for incoming announces with actor being inlined (kroeg)" do
data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
_user = insert(:user, local: false, ap_id: data["actor"]["id"])
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "kroegeroeg"})
data =
data
|> put_in(["object", "id"], post.data["object"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "https://puckipedia.com/"
end
test "it works for incoming announces, fetching the announced object" do
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367")
Tesla.Mock.mock(fn
%{method: :get} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
end)
_user = insert(:user, local: false, ap_id: data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] ==
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
assert(Activity.get_create_by_object_ap_id(data["object"]))
end
@tag capture_log: true
test "it works for incoming announces with an existing activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
_user = insert(:user, local: false, ap_id: data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] == activity.data["object"]
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
# Ignore inlined activities for now
@tag skip: true
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
|> Poison.decode!()
_user =
insert(:user,
local: false,
ap_id: data["actor"],
follower_address: data["actor"] <> "/followers"
)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
object = Object.normalize(data["object"])
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
assert object.data["content"] == "this is a private toot"
end
@tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
Tesla.Mock.mock(fn
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
end)
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
|> Poison.decode!()
_user = insert(:user, local: false, ap_id: data["actor"])
assert {:error, e} = Transmogrifier.handle_incoming(data)
end
test "it does not clobber the addressing on announce activities" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", Object.normalize(activity).data["id"])
|> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
|> Map.put("cc", [])
_user =
insert(:user,
local: false,
ap_id: data["actor"],
follower_address: "http://mastodon.example.org/users/admin/followers"
)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
end
end

View file

@ -28,6 +28,63 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
setup do: clear_config([:instance, :max_remote_account_fields]) setup do: clear_config([:instance, :max_remote_account_fields])
describe "handle_incoming" do describe "handle_incoming" do
test "it works for incoming notices with tag not being an array (kroeg)" do
data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["emoji"] == %{
"icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
}
data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert "test" in object.data["tag"]
end
test "it works for incoming notices with url not being a string (prismo)" do
data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["url"] == "https://prismo.news/posts/83"
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} = activity} = Transmogrifier.handle_incoming(data)
assert data["to"] == []
assert data["cc"] == to
object_data = Object.normalize(activity).data
assert object_data["to"] == []
assert object_data["cc"] == to
end
test "it ignores an incoming notice if we already have it" do test "it ignores an incoming notice if we already have it" do
activity = insert(:note_activity) activity = insert(:note_activity)
@ -260,172 +317,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
"<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>" "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
end end
test "it works for incoming honk announces" do
_user = insert(:user, ap_id: "https://honktest/u/test", local: false)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
announce = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"actor" => "https://honktest/u/test",
"id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
"object" => post.data["object"],
"published" => "2019-06-25T19:33:58Z",
"to" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Announce"
}
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
end
test "it works for incoming announces with actor being inlined (kroeg)" do
data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "https://puckipedia.com/"
end
test "it works for incoming notices with tag not being an array (kroeg)" do
data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["emoji"] == %{
"icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
}
data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert "test" in object.data["tag"]
end
test "it works for incoming notices with url not being a string (prismo)" do
data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["url"] == "https://prismo.news/posts/83"
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} = activity} = Transmogrifier.handle_incoming(data)
assert data["to"] == []
assert data["cc"] == to
object_data = Object.normalize(activity).data
assert object_data["to"] == []
assert object_data["cc"] == to
end
test "it works for incoming announces" do
data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] ==
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
assert Activity.get_create_by_object_ap_id(data["object"])
end
test "it works for incoming announces with an existing activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] == activity.data["object"]
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
|> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
object = Object.normalize(data["object"])
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
assert object.data["content"] == "this is a private toot"
end
@tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
|> Poison.decode!()
assert :error = Transmogrifier.handle_incoming(data)
end
test "it does not clobber the addressing on announce activities" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", Object.normalize(activity).data["id"])
|> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
|> Map.put("cc", [])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
end
test "it ensures that as:Public activities make it to their followers collection" do test "it ensures that as:Public activities make it to their followers collection" do
user = insert(:user) user = insert(:user)
@ -1188,7 +1079,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
{:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
{:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
@ -1438,7 +1329,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
@ -1453,7 +1344,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
@ -1468,7 +1359,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
end end

View file

@ -334,7 +334,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
assert object = Object.normalize(note_activity) assert object = Object.normalize(note_activity)
actor = insert(:user) actor = insert(:user)
{:ok, announce, _object} = ActivityPub.announce(actor, object) {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
assert Utils.get_existing_announce(actor.ap_id, object) == announce assert Utils.get_existing_announce(actor.ap_id, object) == announce
end end
end end

View file

@ -73,7 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
object = Object.normalize(note) object = Object.normalize(note)
user = insert(:user) user = insert(:user)
{:ok, announce_activity, _} = CommonAPI.repeat(note.id, user) {:ok, announce_activity} = CommonAPI.repeat(note.id, user)
result = ObjectView.render("object.json", %{object: announce_activity}) result = ObjectView.render("object.json", %{object: announce_activity})

View file

@ -148,6 +148,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
describe "DELETE /api/pleroma/admin/users" do describe "DELETE /api/pleroma/admin/users" do
test "single user", %{admin: admin, conn: conn} do test "single user", %{admin: admin, conn: conn} do
user = insert(:user) user = insert(:user)
clear_config([:instance, :federating], true)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do publish: fn _ -> nil end do
@ -350,7 +351,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}") conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
assert "Not found" == json_response(conn, 404) assert %{"error" => "Not found"} == json_response(conn, 404)
end end
end end
@ -683,7 +684,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
assert json_response(conn, :bad_request) == assert json_response(conn, :bad_request) ==
%{
"error" =>
"To send invites you need to set the `invites_enabled` option to true." "To send invites you need to set the `invites_enabled` option to true."
}
end end
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
@ -693,7 +697,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
assert json_response(conn, :bad_request) == assert json_response(conn, :bad_request) ==
%{
"error" =>
"To send invites you need to set the `registrations_open` option to false." "To send invites you need to set the `registrations_open` option to false."
}
end end
end end
@ -1307,7 +1314,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
|> json_response(404) |> json_response(404)
assert response == "Not found" assert response == %{"error" => "Not found"}
end end
end end
@ -1413,7 +1420,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
test "with invalid token", %{conn: conn} do test "with invalid token", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
assert json_response(conn, :not_found) == "Not found" assert json_response(conn, :not_found) == %{"error" => "Not found"}
end end
end end
@ -1440,7 +1447,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
test "returns 404 when report id is invalid", %{conn: conn} do test "returns 404 when report id is invalid", %{conn: conn} do
conn = get(conn, "/api/pleroma/admin/reports/test") conn = get(conn, "/api/pleroma/admin/reports/test")
assert json_response(conn, :not_found) == "Not found" assert json_response(conn, :not_found) == %{"error" => "Not found"}
end end
end end
@ -1697,115 +1704,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end end
end end
describe "GET /api/pleroma/admin/statuses/:id" do
test "not found", %{conn: conn} do
assert conn
|> get("/api/pleroma/admin/statuses/not_found")
|> json_response(:not_found)
end
test "shows activity", %{conn: conn} do
activity = insert(:note_activity)
response =
conn
|> get("/api/pleroma/admin/statuses/#{activity.id}")
|> json_response(200)
assert response["id"] == activity.id
end
end
describe "PUT /api/pleroma/admin/statuses/:id" do
setup do
activity = insert(:note_activity)
%{id: activity.id}
end
test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
response =
conn
|> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
|> json_response(:ok)
assert response["sensitive"]
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
response =
conn
|> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
|> json_response(:ok)
refute response["sensitive"]
end
test "change visibility flag", %{conn: conn, id: id, admin: admin} do
response =
conn
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "public"})
|> json_response(:ok)
assert response["visibility"] == "public"
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
response =
conn
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "private"})
|> json_response(:ok)
assert response["visibility"] == "private"
response =
conn
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"})
|> json_response(:ok)
assert response["visibility"] == "unlisted"
end
test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{visibility: "test"})
assert json_response(conn, :bad_request) == "Unsupported visibility"
end
end
describe "DELETE /api/pleroma/admin/statuses/:id" do
setup do
activity = insert(:note_activity)
%{id: activity.id}
end
test "deletes status", %{conn: conn, id: id, admin: admin} do
conn
|> delete("/api/pleroma/admin/statuses/#{id}")
|> json_response(:ok)
refute Activity.get_by_id(id)
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} deleted status ##{id}"
end
test "returns 404 when the status does not exist", %{conn: conn} do
conn = delete(conn, "/api/pleroma/admin/statuses/test")
assert json_response(conn, :not_found) == "Not found"
end
end
describe "GET /api/pleroma/admin/config" do describe "GET /api/pleroma/admin/config" do
setup do: clear_config(:configurable_from_database, true) setup do: clear_config(:configurable_from_database, true)
@ -1814,7 +1712,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = get(conn, "/api/pleroma/admin/config") conn = get(conn, "/api/pleroma/admin/config")
assert json_response(conn, 400) == assert json_response(conn, 400) ==
"To use this endpoint you need to enable configuration from database." %{
"error" => "To use this endpoint you need to enable configuration from database."
}
end end
test "with settings only in db", %{conn: conn} do test "with settings only in db", %{conn: conn} do
@ -1936,7 +1836,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []}) conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
assert json_response(conn, 400) == assert json_response(conn, 400) ==
"To use this endpoint you need to enable configuration from database." %{"error" => "To use this endpoint you need to enable configuration from database."}
end end
describe "POST /api/pleroma/admin/config" do describe "POST /api/pleroma/admin/config" do
@ -2944,6 +2844,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert ":proxy_url" in db assert ":proxy_url" in db
end end
@tag capture_log: true
test "doesn't set keys not in the whitelist", %{conn: conn} do test "doesn't set keys not in the whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [ clear_config(:database_config_whitelist, [
{:pleroma, :key1}, {:pleroma, :key1},
@ -2998,54 +2899,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
on_exit(fn -> Restarter.Pleroma.refresh() end) on_exit(fn -> Restarter.Pleroma.refresh() end)
end end
describe "GET /api/pleroma/admin/statuses" do
test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
blocked = insert(:user)
user = insert(:user)
User.block(admin, blocked)
{:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"})
response =
conn
|> get("/api/pleroma/admin/statuses")
|> json_response(200)
refute "private" in Enum.map(response, & &1["visibility"])
assert length(response) == 3
end
test "returns only local statuses with local_only on", %{conn: conn} do
user = insert(:user)
remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
insert(:note_activity, user: user, local: true)
insert(:note_activity, user: remote_user, local: false)
response =
conn
|> get("/api/pleroma/admin/statuses?local_only=true")
|> json_response(200)
assert length(response) == 1
end
test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
user = insert(:user)
{:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
assert json_response(conn, 200) |> length() == 3
end
end
describe "GET /api/pleroma/admin/users/:nickname/statuses" do describe "GET /api/pleroma/admin/users/:nickname/statuses" do
setup do setup do
user = insert(:user) user = insert(:user)
@ -3096,7 +2949,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
test "excludes reblogs by default", %{conn: conn, user: user} do test "excludes reblogs by default", %{conn: conn, user: user} do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "."}) {:ok, activity} = CommonAPI.post(user, %{status: "."})
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user) {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses") conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
assert json_response(conn_res, 200) |> length() == 0 assert json_response(conn_res, 200) |> length() == 0

View file

@ -0,0 +1,194 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.StatusControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI
setup do
admin = insert(:user, is_admin: true)
token = insert(:oauth_admin_token, user: admin)
conn =
build_conn()
|> assign(:user, admin)
|> assign(:token, token)
{:ok, %{admin: admin, token: token, conn: conn}}
end
describe "GET /api/pleroma/admin/statuses/:id" do
test "not found", %{conn: conn} do
assert conn
|> get("/api/pleroma/admin/statuses/not_found")
|> json_response_and_validate_schema(:not_found)
end
test "shows activity", %{conn: conn} do
activity = insert(:note_activity)
response =
conn
|> get("/api/pleroma/admin/statuses/#{activity.id}")
|> json_response_and_validate_schema(200)
assert response["id"] == activity.id
end
end
describe "PUT /api/pleroma/admin/statuses/:id" do
setup do
activity = insert(:note_activity)
%{id: activity.id}
end
test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
|> json_response_and_validate_schema(:ok)
assert response["sensitive"]
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
|> json_response_and_validate_schema(:ok)
refute response["sensitive"]
end
test "change visibility flag", %{conn: conn, id: id, admin: admin} do
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "public"})
|> json_response_and_validate_schema(:ok)
assert response["visibility"] == "public"
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "private"})
|> json_response_and_validate_schema(:ok)
assert response["visibility"] == "private"
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"})
|> json_response_and_validate_schema(:ok)
assert response["visibility"] == "unlisted"
end
test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
conn =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "test"})
assert %{"error" => "test - Invalid value for enum."} =
json_response_and_validate_schema(conn, :bad_request)
end
end
describe "DELETE /api/pleroma/admin/statuses/:id" do
setup do
activity = insert(:note_activity)
%{id: activity.id}
end
test "deletes status", %{conn: conn, id: id, admin: admin} do
conn
|> delete("/api/pleroma/admin/statuses/#{id}")
|> json_response_and_validate_schema(:ok)
refute Activity.get_by_id(id)
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} deleted status ##{id}"
end
test "returns 404 when the status does not exist", %{conn: conn} do
conn = delete(conn, "/api/pleroma/admin/statuses/test")
assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"}
end
end
describe "GET /api/pleroma/admin/statuses" do
test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
blocked = insert(:user)
user = insert(:user)
User.block(admin, blocked)
{:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"})
response =
conn
|> get("/api/pleroma/admin/statuses")
|> json_response_and_validate_schema(200)
refute "private" in Enum.map(response, & &1["visibility"])
assert length(response) == 3
end
test "returns only local statuses with local_only on", %{conn: conn} do
user = insert(:user)
remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
insert(:note_activity, user: user, local: true)
insert(:note_activity, user: remote_user, local: false)
response =
conn
|> get("/api/pleroma/admin/statuses?local_only=true")
|> json_response_and_validate_schema(200)
assert length(response) == 1
end
test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
user = insert(:user)
{:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
{:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
assert json_response_and_validate_schema(conn, 200) |> length() == 3
end
end
end

View file

@ -116,6 +116,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
clear_config([:instance, :federating], true)
Object.normalize(post, false) Object.normalize(post, false)
|> Object.prune() |> Object.prune()
@ -134,6 +136,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
clear_config([:instance, :federating], true)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do publish: fn _ -> nil end do
assert {:ok, delete} = CommonAPI.delete(post.id, user) assert {:ok, delete} = CommonAPI.delete(post.id, user)
@ -410,6 +414,32 @@ defmodule Pleroma.Web.CommonAPITest do
end) end)
end end
test "replying with a direct message will NOT auto-add the author of the reply to the recipient list" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "I'm stupid"})
{:ok, open_answer} =
CommonAPI.post(other_user, %{status: "No ur smart", in_reply_to_status_id: post.id})
# The OP is implicitly added
assert user.ap_id in open_answer.recipients
{:ok, secret_answer} =
CommonAPI.post(other_user, %{
status: "lol, that guy really is stupid, right, @#{third_user.nickname}?",
in_reply_to_status_id: post.id,
visibility: "direct"
})
assert third_user.ap_id in secret_answer.recipients
# The OP is not added
refute user.ap_id in secret_answer.recipients
end
test "it allows to address a list" do test "it allows to address a list" do
user = insert(:user) user = insert(:user)
{:ok, list} = Pleroma.List.create("foo", user) {:ok, list} = Pleroma.List.create("foo", user)
@ -491,7 +521,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user) {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
assert Visibility.is_public?(announce_activity)
end end
test "can't repeat a repeat" do test "can't repeat a repeat" do
@ -499,9 +530,9 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user) {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user)) refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
end end
test "repeating a status privately" do test "repeating a status privately" do
@ -510,10 +541,11 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce_activity, _} = {:ok, %Activity{} = announce_activity} =
CommonAPI.repeat(activity.id, user, %{visibility: "private"}) CommonAPI.repeat(activity.id, user, %{visibility: "private"})
assert Visibility.is_private?(announce_activity) assert Visibility.is_private?(announce_activity)
refute Visibility.visible_for_user?(announce_activity, nil)
end end
test "favoriting a status" do test "favoriting a status" do
@ -533,8 +565,8 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user) {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
{:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user) {:ok, ^announce} = CommonAPI.repeat(activity.id, user)
end end
test "favoriting a status twice returns ok, but without the like activity" do test "favoriting a status twice returns ok, but without the like activity" do

View file

@ -14,18 +14,41 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
@public_address "https://www.w3.org/ns/activitystreams#Public" @public_address "https://www.w3.org/ns/activitystreams#Public"
test "it adds attachment links to a given text and attachment set" do describe "add_attachments/2" do
setup do
name = name =
"Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png" "Sakura Mana Turned on by a Senior OL with a Temptating Tight Skirt-s Full Hipline and Panty Shot- Beautiful Thick Thighs- and Erotic Ass- -2015- -- Oppaitime 8-28-2017 6-50-33 PM.png"
attachment = %{ attachment = %{
"url" => [%{"href" => name}] "url" => [%{"href" => URI.encode(name)}]
} }
res = Utils.add_attachments("", [attachment]) %{name: name, attachment: attachment}
end
assert res == test "it adds attachment links to a given text and attachment set", %{
"<br><a href=\"#{name}\" class='attachment'>Sakura Mana Turned on by a Se…</a>" name: name,
attachment: attachment
} do
len = 10
clear_config([Pleroma.Upload, :filename_display_max_length], len)
expected =
"<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{String.slice(name, 0..len)}…</a>"
assert Utils.add_attachments("", [attachment]) == expected
end
test "doesn't truncate file name if config for truncate is set to 0", %{
name: name,
attachment: attachment
} do
clear_config([Pleroma.Upload, :filename_display_max_length], 0)
expected = "<br><a href=\"#{URI.encode(name)}\" class='attachment'>#{name}</a>"
assert Utils.add_attachments("", [attachment]) == expected
end
end end
describe "it confirms the password given is the current users password" do describe "it confirms the password given is the current users password" do
@ -297,11 +320,10 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil) {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil)
assert length(to) == 3 assert length(to) == 2
assert Enum.empty?(cc) assert Enum.empty?(cc)
assert mentioned_user.ap_id in to assert mentioned_user.ap_id in to
assert third_user.ap_id in to
assert user.follower_address in to assert user.follower_address in to
end end
@ -327,6 +349,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil) {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil)
assert length(to) == 1
assert Enum.empty?(cc)
assert mentioned_user.ap_id in to
{:ok, direct_activity} = CommonAPI.post(third_user, %{status: "uguu", visibility: "direct"})
{to, cc} = Utils.get_to_and_cc(user, mentions, direct_activity, "direct", nil)
assert length(to) == 2 assert length(to) == 2
assert Enum.empty?(cc) assert Enum.empty?(cc)

View file

@ -256,7 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
User.block(user_one, user_two) User.block(user_one, user_two)
{:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"}) {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
{:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three) {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
assert resp = assert resp =
conn conn
@ -375,7 +375,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "gets a user's statuses without reblogs", %{user: user, conn: conn} do test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
{:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"}) {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
{:ok, _, _} = CommonAPI.repeat(post_id, user) {:ok, _} = CommonAPI.repeat(post_id, user)
conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true") conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200) assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
@ -678,7 +678,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200) assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
{:ok, %{id: reblog_id}, _} = CommonAPI.repeat(activity.id, followed) {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
assert [] == assert [] ==
conn conn

View file

@ -280,8 +280,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, unlisted_activity} = {:ok, unlisted_activity} =
CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"}) CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
{:ok, _, _} = CommonAPI.repeat(public_activity.id, user) {:ok, _} = CommonAPI.repeat(public_activity.id, user)
{:ok, _, _} = CommonAPI.repeat(unlisted_activity.id, user) {:ok, _} = CommonAPI.repeat(unlisted_activity.id, user)
activity_ids = activity_ids =
conn conn
@ -301,7 +301,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
mention_notification_id = get_notification_id_by_activity(mention_activity) mention_notification_id = get_notification_id_by_activity(mention_activity)
@ -339,7 +339,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
mention_notification_id = get_notification_id_by_activity(mention_activity) mention_notification_id = get_notification_id_by_activity(mention_activity)

View file

@ -878,8 +878,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
user3 = insert(:user) user3 = insert(:user)
{:ok, _} = CommonAPI.favorite(user2, activity.id) {:ok, _} = CommonAPI.favorite(user2, activity.id)
{:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
{:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) {:ok, reblog_activity1} = CommonAPI.repeat(activity.id, user1)
{:ok, _, _object} = CommonAPI.repeat(activity.id, user2) {:ok, _} = CommonAPI.repeat(activity.id, user2)
conn_res = conn_res =
build_conn() build_conn()
@ -917,7 +917,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "unreblogs and returns the unreblogged status", %{user: user, conn: conn} do test "unreblogs and returns the unreblogged status", %{user: user, conn: conn} do
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, _, _} = CommonAPI.repeat(activity.id, user) {:ok, _} = CommonAPI.repeat(activity.id, user)
conn = conn =
conn conn
@ -1427,7 +1427,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "returns users who have reblogged the status", %{conn: conn, activity: activity} do test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
other_user = insert(:user) other_user = insert(:user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
conn conn
@ -1458,7 +1458,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, _user_relationship} = User.block(user, other_user) {:ok, _user_relationship} = User.block(user, other_user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
conn conn
@ -1469,12 +1469,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end end
test "does not return users who have reblogged the status privately", %{ test "does not return users who have reblogged the status privately", %{
conn: conn, conn: conn
activity: activity
} do } do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "my secret post"})
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user, %{visibility: "private"}) {:ok, _} = CommonAPI.repeat(activity.id, other_user, %{visibility: "private"})
response = response =
conn conn
@ -1486,7 +1486,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "does not fail on an unauthenticated request", %{activity: activity} do test "does not fail on an unauthenticated request", %{activity: activity} do
other_user = insert(:user) other_user = insert(:user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
build_conn() build_conn()

View file

@ -104,7 +104,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
user = insert(:user) user = insert(:user)
another_user = insert(:user) another_user = insert(:user)
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(reblog_activity) {:ok, [notification]} = Notification.create_notifications(reblog_activity)
reblog_activity = Activity.get_by_id(create_activity.id) reblog_activity = Activity.get_by_id(create_activity.id)

View file

@ -442,7 +442,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
user = insert(:user) user = insert(:user)
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, reblog, _} = CommonAPI.repeat(activity.id, user) {:ok, reblog} = CommonAPI.repeat(activity.id, user)
represented = StatusView.render("show.json", %{for: user, activity: reblog}) represented = StatusView.render("show.json", %{for: user, activity: reblog})
@ -600,7 +600,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status: "˙˙ɐʎns" status: "˙˙ɐʎns"
}) })
{:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user) {:ok, activity} = CommonAPI.repeat(activity.id, other_user)
result = StatusView.render("show.json", %{activity: activity, for: user}) result = StatusView.render("show.json", %{activity: activity, for: user})

View file

@ -10,7 +10,11 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
require Pleroma.Constants
setup_all do setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@ -19,6 +23,47 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
setup do: clear_config([:instance, :federating], true) setup do: clear_config([:instance, :federating], true)
describe "Mastodon compatibility routes" do
setup %{conn: conn} do
conn = put_req_header(conn, "accept", "text/html")
{:ok, object} =
%{
"type" => "Note",
"content" => "hey",
"id" => Endpoint.url() <> "/users/raymoo/statuses/999999999",
"actor" => Endpoint.url() <> "/users/raymoo",
"to" => [Pleroma.Constants.as_public()]
}
|> Object.create()
{:ok, activity, _} =
%{
"id" => object.data["id"] <> "/activity",
"type" => "Create",
"object" => object.data["id"],
"actor" => object.data["actor"],
"to" => object.data["to"]
}
|> ActivityPub.persist(local: true)
%{conn: conn, activity: activity}
end
test "redirects to /notice/:id for html format", %{conn: conn, activity: activity} do
conn = get(conn, "/users/raymoo/statuses/999999999")
assert redirected_to(conn) == "/notice/#{activity.id}"
end
test "redirects to /notice/:id for html format for activity", %{
conn: conn,
activity: activity
} do
conn = get(conn, "/users/raymoo/statuses/999999999/activity")
assert redirected_to(conn) == "/notice/#{activity.id}"
end
end
# Note: see ActivityPubControllerTest for JSON format tests # Note: see ActivityPubControllerTest for JSON format tests
describe "GET /objects/:uuid (text/html)" do describe "GET /objects/:uuid (text/html)" do
setup %{conn: conn} do setup %{conn: conn} do

View file

@ -33,6 +33,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
assert result["pleroma"]["emoji_reactions"] == [ assert result["pleroma"]["emoji_reactions"] == [
%{"name" => "", "count" => 1, "me" => true} %{"name" => "", "count" => 1, "me" => true}
] ]
# Reacting with a non-emoji
assert conn
|> assign(:user, other_user)
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/x")
|> json_response_and_validate_schema(400)
end end
test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do

View file

@ -23,7 +23,8 @@ defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do
response = response =
conn conn
|> post("/api/v1/pleroma/notifications/read?id=#{notification1.id}") |> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/notifications/read", %{id: notification1.id})
|> json_response_and_validate_schema(:ok) |> json_response_and_validate_schema(:ok)
assert %{"pleroma" => %{"is_seen" => true}} = response assert %{"pleroma" => %{"is_seen" => true}} = response
@ -41,7 +42,8 @@ defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do
[response1, response2] = [response1, response2] =
conn conn
|> post("/api/v1/pleroma/notifications/read?max_id=#{notification2.id}") |> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/notifications/read", %{max_id: notification2.id})
|> json_response_and_validate_schema(:ok) |> json_response_and_validate_schema(:ok)
assert %{"pleroma" => %{"is_seen" => true}} = response1 assert %{"pleroma" => %{"is_seen" => true}} = response1
@ -54,7 +56,10 @@ defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do
test "it returns error when notification not found", %{conn: conn} do test "it returns error when notification not found", %{conn: conn} do
response = response =
conn conn
|> post("/api/v1/pleroma/notifications/read?id=22222222222222") |> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/notifications/read", %{
id: 22_222_222_222_222
})
|> json_response_and_validate_schema(:bad_request) |> json_response_and_validate_schema(:bad_request)
assert response == %{"error" => "Cannot get notification"} assert response == %{"error" => "Cannot get notification"}

View file

@ -151,7 +151,7 @@ defmodule Pleroma.Web.Push.ImplTest do
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
}) })
{:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
object = Object.normalize(activity) object = Object.normalize(activity)
assert Impl.format_body(%{activity: announce_activity}, user, object) == assert Impl.format_body(%{activity: announce_activity}, user, object) ==

View file

@ -106,7 +106,7 @@ defmodule Pleroma.Web.StreamerTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user) {:ok, announce} = CommonAPI.repeat(activity.id, user)
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce}
refute Streamer.filtered_by_user?(user, announce) refute Streamer.filtered_by_user?(user, announce)
@ -427,7 +427,7 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"}) {:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1) Streamer.get_topic_and_add_socket("user", user1)
{:ok, announce_activity, _} = CommonAPI.repeat(create_activity.id, user2) {:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, _, ^announce_activity} assert_receive {:render_with_user, _, _, ^announce_activity}
assert Streamer.filtered_by_user?(user1, announce_activity) assert Streamer.filtered_by_user?(user1, announce_activity)
end end
@ -440,7 +440,7 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1) Streamer.get_topic_and_add_socket("user", user1)
{:ok, _favorite_activity, _} = CommonAPI.repeat(create_activity.id, user2) {:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif} assert_receive {:render_with_user, _, "notification.json", notif}
assert Streamer.filtered_by_user?(user1, notif) assert Streamer.filtered_by_user?(user1, notif)

View file

@ -28,6 +28,7 @@ defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
assert email.html_body =~ user.nickname assert email.html_body =~ user.nickname
assert email.html_body =~ user2.nickname assert email.html_body =~ user2.nickname
assert email.html_body =~ "cofe" assert email.html_body =~ "cofe"
assert email.html_body =~ "#{Pleroma.Web.Endpoint.url()}/static/logo.png"
end end
test "it doesn't fail when admin has no email" do test "it doesn't fail when admin has no email" do