Merge branch 'develop' into issue/1383

This commit is contained in:
Maksim Pechnikov 2019-12-08 19:52:46 +03:00
commit 5876a9cb79
55 changed files with 1159 additions and 417 deletions

View file

@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- OStatus: Extract RSS functionality - OStatus: Extract RSS functionality
- Deprecated `User.Info` embedded schema (fields moved to `User`) - Deprecated `User.Info` embedded schema (fields moved to `User`)
- Store status data inside Flag activity - Store status data inside Flag activity
- Deprecated (reorganized as `UserRelationship` entity) User fields with user AP IDs (`blocks`, `mutes`, `muted_reblogs`, `muted_notifications`, `subscribers`).
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>
@ -35,9 +36,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: `pleroma.thread_muted` to the Status entity - Mastodon API: `pleroma.thread_muted` to the Status entity
- Mastodon API: Mark the direct conversation as read for the author when they send a new direct message - Mastodon API: Mark the direct conversation as read for the author when they send a new direct message
- Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload. - Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload.
- Admin API: Render whole status in grouped reports
</details> </details>
### Added ### Added
- `:chat_limit` option to limit chat characters.
- Refreshing poll results for remote polls - Refreshing poll results for remote polls
- Authentication: Added rate limit for password-authorized actions / login existence checks - Authentication: Added rate limit for password-authorized actions / login existence checks
- Static Frontend: Add the ability to render user profiles and notices server-side without requiring JS app. - Static Frontend: Add the ability to render user profiles and notices server-side without requiring JS app.
@ -78,11 +81,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Report emails now include functional links to profiles of remote user accounts - Report emails now include functional links to profiles of remote user accounts
- Not being able to log in to some third-party apps when logged in to MastoFE - Not being able to log in to some third-party apps when logged in to MastoFE
- MRF: `Delete` activities being exempt from MRF policies
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>
- Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`) - Mastodon API: Fix private and direct statuses not being filtered out from the public timeline for an authenticated user (`GET /api/v1/timelines/public`)
- Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname` - Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname`
- AdminAPI: If some status received reports both in the "new" format and "old" format it was considered reports on two different statuses (in the context of grouped reports)
- Admin API: Error when trying to update reports in the "old" format - Admin API: Error when trying to update reports in the "old" format
</details> </details>

View file

@ -211,6 +211,7 @@ config :pleroma, :instance,
notify_email: "noreply@example.com", notify_email: "noreply@example.com",
description: "A Pleroma instance, an alternative fediverse server", description: "A Pleroma instance, an alternative fediverse server",
limit: 5_000, limit: 5_000,
chat_limit: 5_000,
remote_limit: 100_000, remote_limit: 100_000,
upload_limit: 16_000_000, upload_limit: 16_000_000,
avatar_upload_limit: 2_000_000, avatar_upload_limit: 2_000_000,

View file

@ -12,6 +12,7 @@ You shouldn't edit the base config directly to avoid breakages and merge conflic
* `notify_email`: Email used for notifications. * `notify_email`: Email used for notifications.
* `description`: The instances description, can be seen in nodeinfo and ``/api/v1/instance``. * `description`: The instances description, can be seen in nodeinfo and ``/api/v1/instance``.
* `limit`: Posts character limit (CW/Subject included in the counter). * `limit`: Posts character limit (CW/Subject included in the counter).
* `chat_limit`: Character limit of the instance chat messages.
* `remote_limit`: Hard character limit beyond which remote posts will be dropped. * `remote_limit`: Hard character limit beyond which remote posts will be dropped.
* `upload_limit`: File size limit of uploads (except for avatar, background, banner). * `upload_limit`: File size limit of uploads (except for avatar, background, banner).
* `avatar_upload_limit`: File size limit of users profile avatars. * `avatar_upload_limit`: File size limit of users profile avatars.

View file

@ -241,9 +241,10 @@ defmodule Pleroma.Activity do
def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id) def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id)
def normalize(_), do: nil def normalize(_), do: nil
def delete_by_ap_id(id) when is_binary(id) do def delete_all_by_object_ap_id(id) when is_binary(id) do
id id
|> Queries.by_object_id() |> Queries.by_object_id()
|> Queries.exclude_type("Delete")
|> select([u], u) |> select([u], u)
|> Repo.delete_all() |> Repo.delete_all()
|> elem(1) |> elem(1)
@ -255,7 +256,7 @@ defmodule Pleroma.Activity do
|> purge_web_resp_cache() |> purge_web_resp_cache()
end end
def delete_by_ap_id(_), do: nil def delete_all_by_object_ap_id(_), do: nil
defp purge_web_resp_cache(%Activity{} = activity) do defp purge_web_resp_cache(%Activity{} = activity) do
%{path: path} = URI.parse(activity.data["id"]) %{path: path} = URI.parse(activity.data["id"])

View file

@ -64,4 +64,12 @@ defmodule Pleroma.Activity.Queries do
where: fragment("(?)->>'type' = ?", activity.data, ^activity_type) where: fragment("(?)->>'type' = ?", activity.data, ^activity_type)
) )
end end
@spec exclude_type(query, String.t()) :: query
def exclude_type(query \\ Activity, activity_type) do
from(
activity in query,
where: fragment("(?)->>'type' != ?", activity.data, ^activity_type)
)
end
end end

View file

@ -135,8 +135,6 @@ defmodule Pleroma.Application do
[Pleroma.Web.Streamer.supervisor()] [Pleroma.Web.Streamer.supervisor()]
end end
defp chat_child(:test, _), do: []
defp chat_child(_env, true) do defp chat_child(_env, true) do
[Pleroma.Web.ChatChannel.ChatChannelState] [Pleroma.Web.ChatChannel.ChatChannelState]
end end

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Clippy do defmodule Pleroma.Clippy do
@moduledoc false @moduledoc false
# No software is complete until they have a Clippy implementation. # No software is complete until they have a Clippy implementation.
# A ballmer peak _may_ be required to change this module. # A ballmer peak _may_ be required to change this module.

13
lib/pleroma/ecto_enums.ex Normal file
View file

@ -0,0 +1,13 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
import EctoEnum
defenum(UserRelationshipTypeEnum,
block: 1,
mute: 2,
reblog_mute: 3,
notification_mute: 4,
inverse_subscription: 5
)

View file

@ -121,8 +121,12 @@ defmodule Pleroma.FollowingRelationship do
Pleroma.Web.CommonAPI.follow(following_relationship.follower, target) Pleroma.Web.CommonAPI.follow(following_relationship.follower, target)
end) end)
|> case do |> case do
[] -> :ok [] ->
_ -> move_following(origin, target) User.update_follower_count(origin)
:ok
_ ->
move_following(origin, target)
end end
end end
end end

View file

@ -163,6 +163,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
require FastSanitize.Sanitizer.Meta require FastSanitize.Sanitizer.Meta
alias FastSanitize.Sanitizer.Meta alias FastSanitize.Sanitizer.Meta
# credo:disable-for-previous-line # credo:disable-for-previous-line
# No idea how to fix this one… # No idea how to fix this one…

View file

@ -21,6 +21,8 @@ defmodule Pleroma.Notification do
@type t :: %__MODULE__{} @type t :: %__MODULE__{}
@include_muted_option :with_muted
schema "notifications" do schema "notifications" do
field(:seen, :boolean, default: false) field(:seen, :boolean, default: false)
belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
@ -34,7 +36,25 @@ defmodule Pleroma.Notification do
|> cast(attrs, [:seen]) |> cast(attrs, [:seen])
end end
def for_user_query(user, opts \\ []) do defp for_user_query_ap_id_opts(user, opts) do
ap_id_relations =
[:block] ++
if opts[@include_muted_option], do: [], else: [:notification_mute]
preloaded_ap_ids = User.outgoing_relations_ap_ids(user, ap_id_relations)
exclude_blocked_opts = Map.merge(%{blocked_users_ap_ids: preloaded_ap_ids[:block]}, opts)
exclude_notification_muted_opts =
Map.merge(%{notification_muted_users_ap_ids: preloaded_ap_ids[:notification_mute]}, opts)
{exclude_blocked_opts, exclude_notification_muted_opts}
end
def for_user_query(user, opts \\ %{}) do
{exclude_blocked_opts, exclude_notification_muted_opts} =
for_user_query_ap_id_opts(user, opts)
Notification Notification
|> where(user_id: ^user.id) |> where(user_id: ^user.id)
|> where( |> where(
@ -54,33 +74,47 @@ defmodule Pleroma.Notification do
) )
) )
|> preload([n, a, o], activity: {a, object: o}) |> preload([n, a, o], activity: {a, object: o})
|> exclude_muted(user, opts) |> exclude_notification_muted(user, exclude_notification_muted_opts)
|> exclude_blocked(user) |> exclude_blocked(user, exclude_blocked_opts)
|> exclude_visibility(opts) |> exclude_visibility(opts)
|> exclude_move(opts)
end end
defp exclude_blocked(query, user) do defp exclude_blocked(query, user, opts) do
blocked_ap_ids = opts[:blocked_users_ap_ids] || User.blocked_users_ap_ids(user)
query query
|> where([n, a], a.actor not in ^user.blocks) |> where([n, a], a.actor not in ^blocked_ap_ids)
|> where( |> where(
[n, a], [n, a],
fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.domain_blocks fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.domain_blocks
) )
end end
defp exclude_muted(query, _, %{with_muted: true}) do defp exclude_notification_muted(query, _, %{@include_muted_option => true}) do
query query
end end
defp exclude_muted(query, user, _opts) do defp exclude_notification_muted(query, user, opts) do
notification_muted_ap_ids =
opts[:notification_muted_users_ap_ids] || User.notification_muted_users_ap_ids(user)
query query
|> where([n, a], a.actor not in ^user.muted_notifications) |> where([n, a], a.actor not in ^notification_muted_ap_ids)
|> join(:left, [n, a], tm in Pleroma.ThreadMute, |> join(:left, [n, a], tm in Pleroma.ThreadMute,
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data)
) )
|> where([n, a, o, tm], is_nil(tm.user_id)) |> where([n, a, o, tm], is_nil(tm.user_id))
end end
defp exclude_move(query, %{with_move: true}) do
query
end
defp exclude_move(query, _opts) do
where(query, [n, a], fragment("?->>'type' != 'Move'", a.data))
end
@valid_visibilities ~w[direct unlisted public private] @valid_visibilities ~w[direct unlisted public private]
defp exclude_visibility(query, %{exclude_visibilities: visibility}) defp exclude_visibility(query, %{exclude_visibilities: visibility})

View file

@ -147,7 +147,7 @@ defmodule Pleroma.Object do
def delete(%Object{data: %{"id" => id}} = object) do def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object), with {:ok, _obj} = swap_object_with_tombstone(object),
deleted_activity = Activity.delete_by_ap_id(id), deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
{:ok, object, deleted_activity} {:ok, object, deleted_activity}

View file

@ -7,6 +7,7 @@ defmodule Pleroma.User do
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
import Ecto, only: [assoc: 2]
alias Comeonin.Pbkdf2 alias Comeonin.Pbkdf2
alias Ecto.Multi alias Ecto.Multi
@ -21,6 +22,7 @@ defmodule Pleroma.User do
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.RepoStreamer alias Pleroma.RepoStreamer
alias Pleroma.User alias Pleroma.User
alias Pleroma.UserRelationship
alias Pleroma.Web alias Pleroma.Web
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
@ -42,6 +44,32 @@ defmodule Pleroma.User do
@strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/ @strict_local_nickname_regex ~r/^[a-zA-Z\d]+$/
@extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/ @extended_local_nickname_regex ~r/^[a-zA-Z\d_-]+$/
# AP ID user relationships (blocks, mutes etc.)
# Format: [rel_type: [outgoing_rel: :outgoing_rel_target, incoming_rel: :incoming_rel_source]]
@user_relationships_config [
block: [
blocker_blocks: :blocked_users,
blockee_blocks: :blocker_users
],
mute: [
muter_mutes: :muted_users,
mutee_mutes: :muter_users
],
reblog_mute: [
reblog_muter_mutes: :reblog_muted_users,
reblog_mutee_mutes: :reblog_muter_users
],
notification_mute: [
notification_muter_mutes: :notification_muted_users,
notification_mutee_mutes: :notification_muter_users
],
# Note: `inverse_subscription` relationship is inverse: subscriber acts as relationship target
inverse_subscription: [
subscribee_subscriptions: :subscriber_users,
subscriber_subscriptions: :subscribee_users
]
]
schema "users" do schema "users" do
field(:bio, :string) field(:bio, :string)
field(:email, :string) field(:email, :string)
@ -61,7 +89,6 @@ defmodule Pleroma.User do
field(:tags, {:array, :string}, default: []) field(:tags, {:array, :string}, default: [])
field(:last_refreshed_at, :naive_datetime_usec) field(:last_refreshed_at, :naive_datetime_usec)
field(:last_digest_emailed_at, :naive_datetime) field(:last_digest_emailed_at, :naive_datetime)
field(:banner, :map, default: %{}) field(:banner, :map, default: %{})
field(:background, :map, default: %{}) field(:background, :map, default: %{})
field(:source_data, :map, default: %{}) field(:source_data, :map, default: %{})
@ -73,12 +100,7 @@ defmodule Pleroma.User do
field(:password_reset_pending, :boolean, default: false) field(:password_reset_pending, :boolean, default: false)
field(:confirmation_token, :string, default: nil) field(:confirmation_token, :string, default: nil)
field(:default_scope, :string, default: "public") field(:default_scope, :string, default: "public")
field(:blocks, {:array, :string}, default: [])
field(:domain_blocks, {:array, :string}, default: []) field(:domain_blocks, {:array, :string}, default: [])
field(:mutes, {:array, :string}, default: [])
field(:muted_reblogs, {:array, :string}, default: [])
field(:muted_notifications, {:array, :string}, default: [])
field(:subscribers, {:array, :string}, default: [])
field(:deactivated, :boolean, default: false) field(:deactivated, :boolean, default: false)
field(:no_rich_text, :boolean, default: false) field(:no_rich_text, :boolean, default: false)
field(:ap_enabled, :boolean, default: false) field(:ap_enabled, :boolean, default: false)
@ -120,9 +142,82 @@ defmodule Pleroma.User do
has_many(:registrations, Registration) has_many(:registrations, Registration)
has_many(:deliveries, Delivery) has_many(:deliveries, Delivery)
has_many(:outgoing_relationships, UserRelationship, foreign_key: :source_id)
has_many(:incoming_relationships, UserRelationship, foreign_key: :target_id)
for {relationship_type,
[
{outgoing_relation, outgoing_relation_target},
{incoming_relation, incoming_relation_source}
]} <- @user_relationships_config do
# Definitions of `has_many :blocker_blocks`, `has_many :muter_mutes` etc.
has_many(outgoing_relation, UserRelationship,
foreign_key: :source_id,
where: [relationship_type: relationship_type]
)
# Definitions of `has_many :blockee_blocks`, `has_many :mutee_mutes` etc.
has_many(incoming_relation, UserRelationship,
foreign_key: :target_id,
where: [relationship_type: relationship_type]
)
# Definitions of `has_many :blocked_users`, `has_many :muted_users` etc.
has_many(outgoing_relation_target, through: [outgoing_relation, :target])
# Definitions of `has_many :blocker_users`, `has_many :muter_users` etc.
has_many(incoming_relation_source, through: [incoming_relation, :source])
end
# `:blocks` is deprecated (replaced with `blocked_users` relation)
field(:blocks, {:array, :string}, default: [])
# `:mutes` is deprecated (replaced with `muted_users` relation)
field(:mutes, {:array, :string}, default: [])
# `:muted_reblogs` is deprecated (replaced with `reblog_muted_users` relation)
field(:muted_reblogs, {:array, :string}, default: [])
# `:muted_notifications` is deprecated (replaced with `notification_muted_users` relation)
field(:muted_notifications, {:array, :string}, default: [])
# `:subscribers` is deprecated (replaced with `subscriber_users` relation)
field(:subscribers, {:array, :string}, default: [])
timestamps() timestamps()
end end
for {_relationship_type, [{_outgoing_relation, outgoing_relation_target}, _]} <-
@user_relationships_config do
# Definitions of `blocked_users_relation/1`, `muted_users_relation/1`, etc.
def unquote(:"#{outgoing_relation_target}_relation")(user, restrict_deactivated? \\ false) do
target_users_query = assoc(user, unquote(outgoing_relation_target))
if restrict_deactivated? do
restrict_deactivated(target_users_query)
else
target_users_query
end
end
# Definitions of `blocked_users/1`, `muted_users/1`, etc.
def unquote(outgoing_relation_target)(user, restrict_deactivated? \\ false) do
__MODULE__
|> apply(unquote(:"#{outgoing_relation_target}_relation"), [
user,
restrict_deactivated?
])
|> Repo.all()
end
# Definitions of `blocked_users_ap_ids/1`, `muted_users_ap_ids/1`, etc.
def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \\ false) do
__MODULE__
|> apply(unquote(:"#{outgoing_relation_target}_relation"), [
user,
restrict_deactivated?
])
|> select([u], u.ap_id)
|> Repo.all()
end
end
@doc "Returns if the user should be allowed to authenticate" @doc "Returns if the user should be allowed to authenticate"
def auth_active?(%User{deactivated: true}), do: false def auth_active?(%User{deactivated: true}), do: false
@ -946,34 +1041,45 @@ defmodule Pleroma.User do
|> Repo.all() |> Repo.all()
end end
@spec mute(User.t(), User.t(), boolean()) :: {:ok, User.t()} | {:error, String.t()} @spec mute(User.t(), User.t(), boolean()) ::
def mute(muter, %User{ap_id: ap_id}, notifications? \\ true) do {:ok, list(UserRelationship.t())} | {:error, String.t()}
add_to_mutes(muter, ap_id, notifications?) def mute(%User{} = muter, %User{} = mutee, notifications? \\ true) do
add_to_mutes(muter, mutee, notifications?)
end end
def unmute(muter, %{ap_id: ap_id}) do def unmute(%User{} = muter, %User{} = mutee) do
remove_from_mutes(muter, ap_id) remove_from_mutes(muter, mutee)
end end
def subscribe(subscriber, %{ap_id: ap_id}) do def subscribe(%User{} = subscriber, %User{} = target) do
with %User{} = subscribed <- get_cached_by_ap_id(ap_id) do
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
if blocks?(subscribed, subscriber) and deny_follow_blocked do if blocks?(target, subscriber) and deny_follow_blocked do
{:error, "Could not subscribe: #{subscribed.nickname} is blocking you"} {:error, "Could not subscribe: #{target.nickname} is blocking you"}
else else
User.add_to_subscribers(subscribed, subscriber.ap_id) # Note: the relationship is inverse: subscriber acts as relationship target
end UserRelationship.create_inverse_subscription(target, subscriber)
end end
end end
def unsubscribe(unsubscriber, %{ap_id: ap_id}) do def subscribe(%User{} = subscriber, %{ap_id: ap_id}) do
with %User{} = subscribee <- get_cached_by_ap_id(ap_id) do
subscribe(subscriber, subscribee)
end
end
def unsubscribe(%User{} = unsubscriber, %User{} = target) do
# Note: the relationship is inverse: subscriber acts as relationship target
UserRelationship.delete_inverse_subscription(target, unsubscriber)
end
def unsubscribe(%User{} = unsubscriber, %{ap_id: ap_id}) do
with %User{} = user <- get_cached_by_ap_id(ap_id) do with %User{} = user <- get_cached_by_ap_id(ap_id) do
User.remove_from_subscribers(user, unsubscriber.ap_id) unsubscribe(unsubscriber, user)
end end
end end
def block(blocker, %User{ap_id: ap_id} = blocked) do def block(%User{} = blocker, %User{} = blocked) do
# sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213)
blocker = blocker =
if following?(blocker, blocked) do if following?(blocker, blocked) do
@ -990,50 +1096,53 @@ defmodule Pleroma.User do
nil -> blocked nil -> blocked
end end
blocker = unsubscribe(blocked, blocker)
if subscribed_to?(blocked, blocker) do
{:ok, blocker} = unsubscribe(blocked, blocker)
blocker
else
blocker
end
if following?(blocked, blocker), do: unfollow(blocked, blocker) if following?(blocked, blocker), do: unfollow(blocked, blocker)
{:ok, blocker} = update_follower_count(blocker) {:ok, blocker} = update_follower_count(blocker)
{:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked) {:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
add_to_block(blocker, ap_id) add_to_block(blocker, blocked)
end end
# helper to handle the block given only an actor's AP id # helper to handle the block given only an actor's AP id
def block(blocker, %{ap_id: ap_id}) do def block(%User{} = blocker, %{ap_id: ap_id}) do
block(blocker, get_cached_by_ap_id(ap_id)) block(blocker, get_cached_by_ap_id(ap_id))
end end
def unblock(blocker, %{ap_id: ap_id}) do def unblock(%User{} = blocker, %User{} = blocked) do
remove_from_block(blocker, ap_id) remove_from_block(blocker, blocked)
end
# helper to handle the block given only an actor's AP id
def unblock(%User{} = blocker, %{ap_id: ap_id}) do
unblock(blocker, get_cached_by_ap_id(ap_id))
end end
def mutes?(nil, _), do: false def mutes?(nil, _), do: false
def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.mutes, ap_id) def mutes?(%User{} = user, %User{} = target), do: mutes_user?(user, target)
def mutes_user?(%User{} = user, %User{} = target) do
UserRelationship.mute_exists?(user, target)
end
@spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean() @spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean()
def muted_notifications?(nil, _), do: false def muted_notifications?(nil, _), do: false
def muted_notifications?(user, %{ap_id: ap_id}), def muted_notifications?(%User{} = user, %User{} = target),
do: Enum.member?(user.muted_notifications, ap_id) do: UserRelationship.notification_mute_exists?(user, target)
def blocks?(%User{} = user, %User{} = target) do
blocks_ap_id?(user, target) || blocks_domain?(user, target)
end
def blocks?(nil, _), do: false def blocks?(nil, _), do: false
def blocks_ap_id?(%User{} = user, %User{} = target) do def blocks?(%User{} = user, %User{} = target) do
Enum.member?(user.blocks, target.ap_id) blocks_user?(user, target) || blocks_domain?(user, target)
end end
def blocks_ap_id?(_, _), do: false def blocks_user?(%User{} = user, %User{} = target) do
UserRelationship.block_exists?(user, target)
end
def blocks_user?(_, _), do: false
def blocks_domain?(%User{} = user, %User{} = target) do def blocks_domain?(%User{} = user, %User{} = target) do
domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks) domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks)
@ -1043,28 +1152,41 @@ defmodule Pleroma.User do
def blocks_domain?(_, _), do: false def blocks_domain?(_, _), do: false
def subscribed_to?(user, %{ap_id: ap_id}) do def subscribed_to?(%User{} = user, %User{} = target) do
# Note: the relationship is inverse: subscriber acts as relationship target
UserRelationship.inverse_subscription_exists?(target, user)
end
def subscribed_to?(%User{} = user, %{ap_id: ap_id}) do
with %User{} = target <- get_cached_by_ap_id(ap_id) do with %User{} = target <- get_cached_by_ap_id(ap_id) do
Enum.member?(target.subscribers, user.ap_id) subscribed_to?(user, target)
end end
end end
@spec muted_users(User.t()) :: [User.t()] @doc """
def muted_users(user) do Returns map of outgoing (blocked, muted etc.) relations' user AP IDs by relation type.
User.Query.build(%{ap_id: user.mutes, deactivated: false}) E.g. `outgoing_relations_ap_ids(user, [:block])` -> `%{block: ["https://some.site/users/userapid"]}`
|> Repo.all() """
end @spec outgoing_relations_ap_ids(User.t(), list(atom())) :: %{atom() => list(String.t())}
def outgoing_relations_ap_ids(_, []), do: %{}
@spec blocked_users(User.t()) :: [User.t()] def outgoing_relations_ap_ids(%User{} = user, relationship_types)
def blocked_users(user) do when is_list(relationship_types) do
User.Query.build(%{ap_id: user.blocks, deactivated: false}) db_result =
user
|> assoc(:outgoing_relationships)
|> join(:inner, [user_rel], u in assoc(user_rel, :target))
|> where([user_rel, u], user_rel.relationship_type in ^relationship_types)
|> select([user_rel, u], [user_rel.relationship_type, fragment("array_agg(?)", u.ap_id)])
|> group_by([user_rel, u], user_rel.relationship_type)
|> Repo.all() |> Repo.all()
end |> Enum.into(%{}, fn [k, v] -> {k, v} end)
@spec subscribers(User.t()) :: [User.t()] Enum.into(
def subscribers(user) do relationship_types,
User.Query.build(%{ap_id: user.subscribers, deactivated: false}) %{},
|> Repo.all() fn rel_type -> {rel_type, db_result[rel_type] || []} end
)
end end
def deactivate_async(user, status \\ true) do def deactivate_async(user, status \\ true) do
@ -1171,7 +1293,7 @@ defmodule Pleroma.User do
blocked_identifiers, blocked_identifiers,
fn blocked_identifier -> fn blocked_identifier ->
with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier),
{:ok, blocker} <- block(blocker, blocked), {:ok, _user_block} <- block(blocker, blocked),
{:ok, _} <- ActivityPub.block(blocker, blocked) do {:ok, _} <- ActivityPub.block(blocker, blocked) do
blocked blocked
else else
@ -1485,7 +1607,7 @@ defmodule Pleroma.User do
end end
def showing_reblogs?(%User{} = user, %User{} = target) do def showing_reblogs?(%User{} = user, %User{} = target) do
target.ap_id not in user.muted_reblogs not UserRelationship.reblog_mute_exists?(user, target)
end end
@doc """ @doc """
@ -1808,23 +1930,6 @@ defmodule Pleroma.User do
|> update_and_set_cache() |> update_and_set_cache()
end end
defp set_subscribers(user, subscribers) do
params = %{subscribers: subscribers}
user
|> cast(params, [:subscribers])
|> validate_required([:subscribers])
|> update_and_set_cache()
end
def add_to_subscribers(user, subscribed) do
set_subscribers(user, Enum.uniq([subscribed | user.subscribers]))
end
def remove_from_subscribers(user, subscribed) do
set_subscribers(user, List.delete(user.subscribers, subscribed))
end
defp set_domain_blocks(user, domain_blocks) do defp set_domain_blocks(user, domain_blocks) do
params = %{domain_blocks: domain_blocks} params = %{domain_blocks: domain_blocks}
@ -1842,81 +1947,35 @@ defmodule Pleroma.User do
set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked)) set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked))
end end
defp set_blocks(user, blocks) do @spec add_to_block(User.t(), User.t()) ::
params = %{blocks: blocks} {:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()}
defp add_to_block(%User{} = user, %User{} = blocked) do
user UserRelationship.create_block(user, blocked)
|> cast(params, [:blocks])
|> validate_required([:blocks])
|> update_and_set_cache()
end end
def add_to_block(user, blocked) do @spec add_to_block(User.t(), User.t()) ::
set_blocks(user, Enum.uniq([blocked | user.blocks])) {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()}
defp remove_from_block(%User{} = user, %User{} = blocked) do
UserRelationship.delete_block(user, blocked)
end end
def remove_from_block(user, blocked) do defp add_to_mutes(%User{} = user, %User{} = muted_user, notifications?) do
set_blocks(user, List.delete(user.blocks, blocked)) with {:ok, user_mute} <- UserRelationship.create_mute(user, muted_user),
end {:ok, user_notification_mute} <-
(notifications? && UserRelationship.create_notification_mute(user, muted_user)) ||
defp set_mutes(user, mutes) do {:ok, nil} do
params = %{mutes: mutes} {:ok, Enum.filter([user_mute, user_notification_mute], & &1)}
user
|> cast(params, [:mutes])
|> validate_required([:mutes])
|> update_and_set_cache()
end
def add_to_mutes(user, muted, notifications?) do
with {:ok, user} <- set_mutes(user, Enum.uniq([muted | user.mutes])) do
set_notification_mutes(
user,
Enum.uniq([muted | user.muted_notifications]),
notifications?
)
end end
end end
def remove_from_mutes(user, muted) do defp remove_from_mutes(user, %User{} = muted_user) do
with {:ok, user} <- set_mutes(user, List.delete(user.mutes, muted)) do with {:ok, user_mute} <- UserRelationship.delete_mute(user, muted_user),
set_notification_mutes( {:ok, user_notification_mute} <-
user, UserRelationship.delete_notification_mute(user, muted_user) do
List.delete(user.muted_notifications, muted), {:ok, [user_mute, user_notification_mute]}
true
)
end end
end end
defp set_notification_mutes(user, _muted_notifications, false = _notifications?) do
{:ok, user}
end
defp set_notification_mutes(user, muted_notifications, true = _notifications?) do
params = %{muted_notifications: muted_notifications}
user
|> cast(params, [:muted_notifications])
|> validate_required([:muted_notifications])
|> update_and_set_cache()
end
def add_reblog_mute(user, ap_id) do
params = %{muted_reblogs: user.muted_reblogs ++ [ap_id]}
user
|> cast(params, [:muted_reblogs])
|> update_and_set_cache()
end
def remove_reblog_mute(user, ap_id) do
params = %{muted_reblogs: List.delete(user.muted_reblogs, ap_id)}
user
|> cast(params, [:muted_reblogs])
|> update_and_set_cache()
end
def set_invisible(user, invisible) do def set_invisible(user, invisible) do
params = %{invisible: invisible} params = %{invisible: invisible}

View file

@ -103,9 +103,13 @@ defmodule Pleroma.User.Search do
from(q in query, where: q.invisible == false) from(q in query, where: q.invisible == false)
end end
defp filter_blocked_user(query, %User{blocks: blocks}) defp filter_blocked_user(query, %User{} = blocker) do
when length(blocks) > 0 do query
from(q in query, where: not (q.ap_id in ^blocks)) |> join(:left, [u], b in Pleroma.UserRelationship,
as: :blocks,
on: b.relationship_type == ^:block and b.source_id == ^blocker.id and u.id == b.target_id
)
|> where([blocks: b], is_nil(b.target_id))
end end
defp filter_blocked_user(query, _), do: query defp filter_blocked_user(query, _), do: query

View file

@ -0,0 +1,92 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserRelationship do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.UserRelationship
schema "user_relationships" do
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
field(:relationship_type, UserRelationshipTypeEnum)
timestamps(updated_at: false)
end
for relationship_type <- Keyword.keys(UserRelationshipTypeEnum.__enum_map__()) do
# Definitions of `create_block/2`, `create_mute/2` etc.
def unquote(:"create_#{relationship_type}")(source, target),
do: create(unquote(relationship_type), source, target)
# Definitions of `delete_block/2`, `delete_mute/2` etc.
def unquote(:"delete_#{relationship_type}")(source, target),
do: delete(unquote(relationship_type), source, target)
# Definitions of `block_exists?/2`, `mute_exists?/2` etc.
def unquote(:"#{relationship_type}_exists?")(source, target),
do: exists?(unquote(relationship_type), source, target)
end
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
user_relationship
|> cast(params, [:relationship_type, :source_id, :target_id])
|> validate_required([:relationship_type, :source_id, :target_id])
|> unique_constraint(:relationship_type,
name: :user_relationships_source_id_relationship_type_target_id_index
)
|> validate_not_self_relationship()
end
def exists?(relationship_type, %User{} = source, %User{} = target) do
UserRelationship
|> where(relationship_type: ^relationship_type, source_id: ^source.id, target_id: ^target.id)
|> Repo.exists?()
end
def create(relationship_type, %User{} = source, %User{} = target) do
%UserRelationship{}
|> changeset(%{
relationship_type: relationship_type,
source_id: source.id,
target_id: target.id
})
|> Repo.insert(
on_conflict: :replace_all_except_primary_key,
conflict_target: [:source_id, :relationship_type, :target_id]
)
end
def delete(relationship_type, %User{} = source, %User{} = target) do
attrs = %{relationship_type: relationship_type, source_id: source.id, target_id: target.id}
case Repo.get_by(UserRelationship, attrs) do
%UserRelationship{} = existing_record -> Repo.delete(existing_record)
nil -> {:ok, nil}
end
end
defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
changeset
|> validate_change(:target_id, fn _, target_id ->
if target_id == get_field(changeset, :source_id) do
[target_id: "can't be equal to source_id"]
else
[]
end
end)
|> validate_change(:source_id, fn _, source_id ->
if source_id == get_field(changeset, :target_id) do
[source_id: "can't be equal to target_id"]
else
[]
end
end)
end
end

View file

@ -456,17 +456,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
user = User.get_cached_by_ap_id(actor) user = User.get_cached_by_ap_id(actor)
to = (object.data["to"] || []) ++ (object.data["cc"] || []) to = (object.data["to"] || []) ++ (object.data["cc"] || [])
with {:ok, object, activity} <- Object.delete(object), with create_activity <- Activity.get_create_by_object_ap_id(id),
data <- data <-
%{ %{
"type" => "Delete", "type" => "Delete",
"actor" => actor, "actor" => actor,
"object" => id, "object" => id,
"to" => to, "to" => to,
"deleted_activity_id" => activity && activity.id "deleted_activity_id" => create_activity && create_activity.id
} }
|> maybe_put("id", activity_id), |> maybe_put("id", activity_id),
{:ok, activity} <- insert(data, local, false), {:ok, activity} <- insert(data, local, false),
{:ok, object, _create_activity} <- Object.delete(object),
stream_out_participations(object, user), stream_out_participations(object, user),
_ <- decrease_replies_count_if_reply(object), _ <- decrease_replies_count_if_reply(object),
{:ok, _actor} <- decrease_note_count_if_public(user, object), {:ok, _actor} <- decrease_note_count_if_public(user, object),
@ -748,6 +749,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> Map.put("whole_db", true) |> Map.put("whole_db", true)
|> Map.put("pinned_activity_ids", user.pinned_activities) |> Map.put("pinned_activity_ids", user.pinned_activities)
params =
if User.blocks?(reading_user, user) do
params
else
params
|> Map.put("blocking_user", reading_user)
|> Map.put("muting_user", reading_user)
end
recipients = recipients =
user_activities_recipients(%{ user_activities_recipients(%{
"godmode" => params["godmode"], "godmode" => params["godmode"],
@ -919,7 +929,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do
mutes = user.mutes mutes = opts["muted_users_ap_ids"] || User.muted_users_ap_ids(user)
query = query =
from([activity] in query, from([activity] in query,
@ -936,8 +946,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_muted(query, _), do: query defp restrict_muted(query, _), do: query
defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do defp restrict_blocked(query, %{"blocking_user" => %User{} = user} = opts) do
blocks = user.blocks || [] blocked_ap_ids = opts["blocked_users_ap_ids"] || User.blocked_users_ap_ids(user)
domain_blocks = user.domain_blocks || [] domain_blocks = user.domain_blocks || []
query = query =
@ -945,14 +955,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
from( from(
[activity, object: o] in query, [activity, object: o] in query,
where: fragment("not (? = ANY(?))", activity.actor, ^blocks), where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
where: fragment("not (? && ?)", activity.recipients, ^blocks), where: fragment("not (? && ?)", activity.recipients, ^blocked_ap_ids),
where: where:
fragment( fragment(
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)", "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
activity.data, activity.data,
activity.data, activity.data,
^blocks ^blocked_ap_ids
), ),
where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks), where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks),
where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks) where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks)
@ -979,8 +989,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_pinned(query, _), do: query defp restrict_pinned(query, _), do: query
defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user} = opts) do
muted_reblogs = user.muted_reblogs || [] muted_reblogs = opts["reblog_muted_users_ap_ids"] || User.reblog_muted_users_ap_ids(user)
from( from(
activity in query, activity in query,
@ -1061,7 +1071,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp maybe_order(query, _), do: query defp maybe_order(query, _), do: query
defp fetch_activities_query_ap_ids_ops(opts) do
source_user = opts["muting_user"]
ap_id_relations = if source_user, do: [:mute, :reblog_mute], else: []
ap_id_relations =
ap_id_relations ++
if opts["blocking_user"] && opts["blocking_user"] == source_user do
[:block]
else
[]
end
preloaded_ap_ids = User.outgoing_relations_ap_ids(source_user, ap_id_relations)
restrict_blocked_opts = Map.merge(%{"blocked_users_ap_ids" => preloaded_ap_ids[:block]}, opts)
restrict_muted_opts = Map.merge(%{"muted_users_ap_ids" => preloaded_ap_ids[:mute]}, opts)
restrict_muted_reblogs_opts =
Map.merge(%{"reblog_muted_users_ap_ids" => preloaded_ap_ids[:reblog_mute]}, opts)
{restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts}
end
def fetch_activities_query(recipients, opts \\ %{}) do def fetch_activities_query(recipients, opts \\ %{}) do
{restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts} =
fetch_activities_query_ap_ids_ops(opts)
config = %{ config = %{
skip_thread_containment: Config.get([:instance, :skip_thread_containment]) skip_thread_containment: Config.get([:instance, :skip_thread_containment])
} }
@ -1081,15 +1117,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_type(opts) |> restrict_type(opts)
|> restrict_state(opts) |> restrict_state(opts)
|> restrict_favorited_by(opts) |> restrict_favorited_by(opts)
|> restrict_blocked(opts) |> restrict_blocked(restrict_blocked_opts)
|> restrict_muted(opts) |> restrict_muted(restrict_muted_opts)
|> restrict_media(opts) |> restrict_media(opts)
|> restrict_visibility(opts) |> restrict_visibility(opts)
|> restrict_thread_visibility(opts, config) |> restrict_thread_visibility(opts, config)
|> restrict_replies(opts) |> restrict_replies(opts)
|> restrict_reblogs(opts) |> restrict_reblogs(opts)
|> restrict_pinned(opts) |> restrict_pinned(opts)
|> restrict_muted_reblogs(opts) |> restrict_muted_reblogs(restrict_muted_reblogs_opts)
|> restrict_instance(opts) |> restrict_instance(opts)
|> Activity.restrict_deactivated_users() |> Activity.restrict_deactivated_users()
|> exclude_poll_votes(opts) |> exclude_poll_votes(opts)

View file

@ -387,7 +387,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming(%{"id" => nil}, _options), do: :error def handle_incoming(%{"id" => nil}, _options), do: :error
def handle_incoming(%{"id" => ""}, _options), do: :error def handle_incoming(%{"id" => ""}, _options), do: :error
# length of https:// = 8, should validate better, but good enough for now. # length of https:// = 8, should validate better, but good enough for now.
def handle_incoming(%{"id" => id}, _options) when not (is_binary(id) and length(id) > 8), def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8,
do: :error do: :error
# TODO: validate those with a Ecto scheme # TODO: validate those with a Ecto scheme

View file

@ -722,16 +722,22 @@ defmodule Pleroma.Web.ActivityPub.Utils do
act when is_binary(act) -> act act when is_binary(act) -> act
end end
activity = Activity.get_by_ap_id_with_object(id) case Activity.get_by_ap_id_with_object(id) do
actor = User.get_by_ap_id(activity.object.data["actor"]) %Activity{} = activity ->
%{ %{
"type" => "Note", "type" => "Note",
"id" => activity.data["id"], "id" => activity.data["id"],
"content" => activity.object.data["content"], "content" => activity.object.data["content"],
"published" => activity.object.data["published"], "published" => activity.object.data["published"],
"actor" => AccountView.render("show.json", %{user: actor}) "actor" =>
AccountView.render("show.json", %{
user: User.get_by_ap_id(activity.object.data["actor"])
})
} }
_ ->
%{"id" => id, "deleted" => true}
end
end end
defp build_flag_object(_), do: [] defp build_flag_object(_), do: []
@ -788,7 +794,52 @@ defmodule Pleroma.Web.ActivityPub.Utils do
ActivityPub.fetch_activities([], params, :offset) ActivityPub.fetch_activities([], params, :offset)
end end
@spec get_reports_grouped_by_status(%{required(:activity) => String.t()}) :: %{ def parse_report_group(activity) do
reports = get_reports_by_status_id(activity["id"])
max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"]))
actors = Enum.map(reports, & &1.user_actor)
[%{data: %{"object" => [account_id | _]}} | _] = reports
account =
AccountView.render("show.json", %{
user: User.get_by_ap_id(account_id)
})
status = get_status_data(activity)
%{
date: max_date.data["published"],
account: account,
status: status,
actors: Enum.uniq(actors),
reports: reports
}
end
defp get_status_data(status) do
case status["deleted"] do
true ->
%{
"id" => status["id"],
"deleted" => true
}
_ ->
Activity.get_by_ap_id(status["id"])
end
end
def get_reports_by_status_id(ap_id) do
from(a in Activity,
where: fragment("(?)->>'type' = 'Flag'", a.data),
where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}]),
or_where: fragment("(?)->'object' @> ?", a.data, ^[ap_id])
)
|> Activity.with_preloaded_user_actor()
|> Repo.all()
end
@spec get_reports_grouped_by_status([String.t()]) :: %{
required(:groups) => [ required(:groups) => [
%{ %{
required(:date) => String.t(), required(:date) => String.t(),
@ -797,20 +848,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do
required(:actors) => [%User{}], required(:actors) => [%User{}],
required(:reports) => [%Activity{}] required(:reports) => [%Activity{}]
} }
], ]
required(:total) => integer
} }
def get_reports_grouped_by_status(groups) do def get_reports_grouped_by_status(activity_ids) do
parsed_groups = parsed_groups =
groups activity_ids
|> Enum.map(fn entry -> |> Enum.map(fn id ->
activity = id
case Jason.decode(entry.activity) do |> build_flag_object()
{:ok, activity} -> activity |> parse_report_group()
_ -> build_flag_object(entry.activity)
end
parse_report_group(activity)
end) end)
%{ %{
@ -818,33 +864,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
} }
end end
def parse_report_group(activity) do
reports = get_reports_by_status_id(activity["id"])
max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"]))
actors = Enum.map(reports, & &1.user_actor)
%{
date: max_date.data["published"],
account: activity["actor"],
status: %{
id: activity["id"],
content: activity["content"],
published: activity["published"]
},
actors: Enum.uniq(actors),
reports: reports
}
end
def get_reports_by_status_id(ap_id) do
from(a in Activity,
where: fragment("(?)->>'type' = 'Flag'", a.data),
where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}])
)
|> Activity.with_preloaded_user_actor()
|> Repo.all()
end
@spec get_reported_activities() :: [ @spec get_reported_activities() :: [
%{ %{
required(:activity) => String.t(), required(:activity) => String.t(),
@ -852,17 +871,23 @@ defmodule Pleroma.Web.ActivityPub.Utils do
} }
] ]
def get_reported_activities do def get_reported_activities do
reported_activities_query =
from(a in Activity, from(a in Activity,
where: fragment("(?)->>'type' = 'Flag'", a.data), where: fragment("(?)->>'type' = 'Flag'", a.data),
select: %{ select: %{
date: fragment("max(?->>'published') date", a.data), activity: fragment("jsonb_array_elements((? #- '{object,0}')->'object')", a.data)
activity:
fragment("jsonb_array_elements_text((? #- '{object,0}')->'object') activity", a.data)
}, },
group_by: fragment("activity"), group_by: fragment("activity")
order_by: fragment("date DESC") )
from(a in subquery(reported_activities_query),
distinct: true,
select: %{
id: fragment("COALESCE(?->>'id'::text, ? #>> '{}')", a.activity, a.activity)
}
) )
|> Repo.all() |> Repo.all()
|> Enum.map(& &1.id)
end end
def update_report_state(%Activity{} = activity, state) def update_report_state(%Activity{} = activity, state)

View file

@ -647,11 +647,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end end
def list_grouped_reports(conn, _params) do def list_grouped_reports(conn, _params) do
reports = Utils.get_reported_activities() statuses = Utils.get_reported_activities()
conn conn
|> put_view(ReportView) |> put_view(ReportView)
|> render("index_grouped.json", Utils.get_reports_grouped_by_status(reports)) |> render("index_grouped.json", Utils.get_reports_grouped_by_status(statuses))
end end
def report_show(conn, %{"id" => id}) do def report_show(conn, %{"id" => id}) do

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Web.AdminAPI.ReportView do defmodule Pleroma.Web.AdminAPI.ReportView do
use Pleroma.Web, :view use Pleroma.Web, :view
alias Pleroma.Activity
alias Pleroma.HTML alias Pleroma.HTML
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.AdminAPI.Report alias Pleroma.Web.AdminAPI.Report
@ -45,10 +46,16 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
def render("index_grouped.json", %{groups: groups}) do def render("index_grouped.json", %{groups: groups}) do
reports = reports =
Enum.map(groups, fn group -> Enum.map(groups, fn group ->
status =
case group.status do
%Activity{} = activity -> StatusView.render("show.json", %{activity: activity})
_ -> group.status
end
%{ %{
date: group[:date], date: group[:date],
account: group[:account], account: group[:account],
status: group[:status], status: Map.put_new(status, "deleted", false),
actors: Enum.map(group[:actors], &merge_account_views/1), actors: Enum.map(group[:actors], &merge_account_views/1),
reports: reports:
group[:reports] group[:reports]

View file

@ -20,7 +20,7 @@ defmodule Pleroma.Web.ChatChannel do
def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do
text = String.trim(text) text = String.trim(text)
if String.length(text) > 0 do if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
author = User.get_cached_by_nickname(user_name) author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author) author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
message = ChatChannelState.add_message(%{text: text, author: author}) message = ChatChannelState.add_message(%{text: text, author: author})

View file

@ -10,6 +10,7 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.ThreadMute alias Pleroma.ThreadMute
alias Pleroma.User alias Pleroma.User
alias Pleroma.UserRelationship
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
@ -32,7 +33,7 @@ defmodule Pleroma.Web.CommonAPI do
def unfollow(follower, unfollowed) do def unfollow(follower, unfollowed) do
with {:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed), with {:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed),
{:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed), {:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed),
{:ok, _unfollowed} <- User.unsubscribe(follower, unfollowed) do {:ok, _subscription} <- User.unsubscribe(follower, unfollowed) do
{:ok, follower} {:ok, follower}
end end
end end
@ -420,15 +421,11 @@ defmodule Pleroma.Web.CommonAPI do
defp set_visibility(activity, _), do: {:ok, activity} defp set_visibility(activity, _), do: {:ok, activity}
def hide_reblogs(user, %{ap_id: ap_id} = _muted) do def hide_reblogs(%User{} = user, %User{} = target) do
if ap_id not in user.muted_reblogs do UserRelationship.create_reblog_mute(user, target)
User.add_reblog_mute(user, ap_id)
end
end end
def show_reblogs(user, %{ap_id: ap_id} = _muted) do def show_reblogs(%User{} = user, %User{} = target) do
if ap_id in user.muted_reblogs do UserRelationship.delete_reblog_mute(user, target)
User.remove_reblog_mute(user, ap_id)
end
end end
end end

View file

@ -494,7 +494,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
with %User{} = user <- User.get_cached_by_ap_id(actor) do with %User{} = user <- User.get_cached_by_ap_id(actor) do
subscriber_ids = subscriber_ids =
user user
|> User.subscribers() |> User.subscriber_users()
|> Enum.filter(&Visibility.visible_for_user?(activity, &1)) |> Enum.filter(&Visibility.visible_for_user?(activity, &1))
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)

View file

@ -249,7 +249,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "GET /api/v1/accounts/:id/statuses" @doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do def statuses(%{assigns: %{user: reading_user}} = conn, params) do
with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
params = Map.put(params, "tag", params["tagged"]) params =
params
|> Map.put("tag", params["tagged"])
|> Map.delete("godmode")
activities = ActivityPub.fetch_user_activities(user, reading_user, params) activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn conn
@ -324,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
def mute(%{assigns: %{user: muter, account: muted}} = conn, params) do def mute(%{assigns: %{user: muter, account: muted}} = conn, params) do
notifications? = params |> Map.get("notifications", true) |> truthy_param?() notifications? = params |> Map.get("notifications", true) |> truthy_param?()
with {:ok, muter} <- User.mute(muter, muted, notifications?) do with {:ok, _user_relationships} <- User.mute(muter, muted, notifications?) do
render(conn, "relationship.json", user: muter, target: muted) render(conn, "relationship.json", user: muter, target: muted)
else else
{:error, message} -> json_response(conn, :forbidden, %{error: message}) {:error, message} -> json_response(conn, :forbidden, %{error: message})
@ -333,7 +337,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts/:id/unmute" @doc "POST /api/v1/accounts/:id/unmute"
def unmute(%{assigns: %{user: muter, account: muted}} = conn, _params) do def unmute(%{assigns: %{user: muter, account: muted}} = conn, _params) do
with {:ok, muter} <- User.unmute(muter, muted) do with {:ok, _user_relationships} <- User.unmute(muter, muted) do
render(conn, "relationship.json", user: muter, target: muted) render(conn, "relationship.json", user: muter, target: muted)
else else
{:error, message} -> json_response(conn, :forbidden, %{error: message}) {:error, message} -> json_response(conn, :forbidden, %{error: message})
@ -342,7 +346,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts/:id/block" @doc "POST /api/v1/accounts/:id/block"
def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
with {:ok, blocker} <- User.block(blocker, blocked), with {:ok, _user_block} <- User.block(blocker, blocked),
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do {:ok, _activity} <- ActivityPub.block(blocker, blocked) do
render(conn, "relationship.json", user: blocker, target: blocked) render(conn, "relationship.json", user: blocker, target: blocked)
else else
@ -352,7 +356,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts/:id/unblock" @doc "POST /api/v1/accounts/:id/unblock"
def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
with {:ok, blocker} <- User.unblock(blocker, blocked), with {:ok, _user_block} <- User.unblock(blocker, blocked),
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do {:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
render(conn, "relationship.json", user: blocker, target: blocked) render(conn, "relationship.json", user: blocker, target: blocked)
else else
@ -374,12 +378,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "GET /api/v1/mutes" @doc "GET /api/v1/mutes"
def mutes(%{assigns: %{user: user}} = conn, _) do def mutes(%{assigns: %{user: user}} = conn, _) do
render(conn, "index.json", users: User.muted_users(user), for: user, as: :user) users = User.muted_users(user, _restrict_deactivated = true)
render(conn, "index.json", users: users, for: user, as: :user)
end end
@doc "GET /api/v1/blocks" @doc "GET /api/v1/blocks"
def blocks(%{assigns: %{user: user}} = conn, _) do def blocks(%{assigns: %{user: user}} = conn, _) do
render(conn, "index.json", users: User.blocked_users(user), for: user, as: :user) users = User.blocked_users(user, _restrict_deactivated = true)
render(conn, "index.json", users: users, for: user, as: :user)
end end
@doc "GET /api/v1/endorsements" @doc "GET /api/v1/endorsements"

View file

@ -24,19 +24,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
with {:ok, follower, _followed, _} <- result do with {:ok, follower, _followed, _} <- result do
options = cast_params(params) options = cast_params(params)
set_reblogs_visibility(options[:reblogs], result)
case reblogs_visibility(options[:reblogs], result) do {:ok, follower}
{:ok, follower} -> {:ok, follower}
_ -> {:ok, follower}
end
end end
end end
defp reblogs_visibility(false, {:ok, follower, followed, _}) do defp set_reblogs_visibility(false, {:ok, follower, followed, _}) do
CommonAPI.hide_reblogs(follower, followed) CommonAPI.hide_reblogs(follower, followed)
end end
defp reblogs_visibility(_, {:ok, follower, followed, _}) do defp set_reblogs_visibility(_, {:ok, follower, followed, _}) do
CommonAPI.show_reblogs(follower, followed) CommonAPI.show_reblogs(follower, followed)
end end
@ -73,7 +70,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
exclude_types: {:array, :string}, exclude_types: {:array, :string},
exclude_visibilities: {:array, :string}, exclude_visibilities: {:array, :string},
reblogs: :boolean, reblogs: :boolean,
with_muted: :boolean with_muted: :boolean,
with_move: :boolean
} }
changeset = cast({%{}, param_types}, params, Map.keys(param_types)) changeset = cast({%{}, param_types}, params, Map.keys(param_types))

View file

@ -50,8 +50,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
id: to_string(target.id), id: to_string(target.id),
following: User.following?(user, target), following: User.following?(user, target),
followed_by: User.following?(target, user), followed_by: User.following?(target, user),
blocking: User.blocks_ap_id?(user, target), blocking: User.blocks_user?(user, target),
blocked_by: User.blocks_ap_id?(target, user), blocked_by: User.blocks_user?(target, user),
muting: User.mutes?(user, target), muting: User.mutes?(user, target),
muting_notifications: User.muted_notifications?(user, target), muting_notifications: User.muted_notifications?(user, target),
subscribing: User.subscribed_to?(user, target), subscribing: User.subscribed_to?(user, target),

View file

@ -144,7 +144,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
@doc "POST /api/v1/pleroma/accounts/:id/subscribe" @doc "POST /api/v1/pleroma/accounts/:id/subscribe"
def subscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do def subscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do
with {:ok, subscription_target} <- User.subscribe(user, subscription_target) do with {:ok, _subscription} <- User.subscribe(user, subscription_target) do
render(conn, "relationship.json", user: user, target: subscription_target) render(conn, "relationship.json", user: user, target: subscription_target)
else else
{:error, message} -> json_response(conn, :forbidden, %{error: message}) {:error, message} -> json_response(conn, :forbidden, %{error: message})
@ -153,7 +153,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
@doc "POST /api/v1/pleroma/accounts/:id/unsubscribe" @doc "POST /api/v1/pleroma/accounts/:id/unsubscribe"
def unsubscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do def unsubscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do
with {:ok, subscription_target} <- User.unsubscribe(user, subscription_target) do with {:ok, _subscription} <- User.unsubscribe(user, subscription_target) do
render(conn, "relationship.json", user: user, target: subscription_target) render(conn, "relationship.json", user: user, target: subscription_target)
else else
{:error, message} -> json_response(conn, :forbidden, %{error: message}) {:error, message} -> json_response(conn, :forbidden, %{error: message})

View file

@ -129,16 +129,17 @@ defmodule Pleroma.Web.Streamer.Worker do
end end
defp should_send?(%User{} = user, %Activity{} = item) do defp should_send?(%User{} = user, %Activity{} = item) do
blocks = user.blocks || [] %{block: blocked_ap_ids, mute: muted_ap_ids, reblog_mute: reblog_muted_ap_ids} =
mutes = user.mutes || [] User.outgoing_relations_ap_ids(user, [:block, :mute, :reblog_mute])
reblog_mutes = user.muted_reblogs || []
recipient_blocks = MapSet.new(blocks ++ mutes) recipient_blocks = MapSet.new(blocked_ap_ids ++ muted_ap_ids)
recipients = MapSet.new(item.recipients) recipients = MapSet.new(item.recipients)
domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks) domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks)
with parent <- Object.normalize(item) || item, with parent <- Object.normalize(item) || item,
true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), true <-
true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), Enum.all?([blocked_ap_ids, muted_ap_ids, reblog_muted_ap_ids], &(item.actor not in &1)),
true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)),
true <- MapSet.disjoint?(recipients, recipient_blocks), true <- MapSet.disjoint?(recipients, recipient_blocks),
%{host: item_host} <- URI.parse(item.actor), %{host: item_host} <- URI.parse(item.actor),
%{host: parent_host} <- URI.parse(parent.data["actor"]), %{host: parent_host} <- URI.parse(parent.data["actor"]),

View file

@ -100,6 +100,7 @@ defmodule Pleroma.Mixfile do
{:plug_cowboy, "~> 2.0"}, {:plug_cowboy, "~> 2.0"},
{:phoenix_pubsub, "~> 1.1"}, {:phoenix_pubsub, "~> 1.1"},
{:phoenix_ecto, "~> 4.0"}, {:phoenix_ecto, "~> 4.0"},
{:ecto_enum, "~> 1.4"},
{:ecto_sql, "~> 3.2"}, {:ecto_sql, "~> 3.2"},
{:postgrex, ">= 0.13.5"}, {:postgrex, ">= 0.13.5"},
{:oban, "~> 0.12.0"}, {:oban, "~> 0.12.0"},

View file

@ -24,6 +24,7 @@
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "3.2.5", "76c864b77948a479e18e69cc1d0f0f4ee7cced1148ffe6a093ff91eba644f0b5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "3.2.5", "76c864b77948a479e18e69cc1d0f0f4ee7cced1148ffe6a093ff91eba644f0b5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.2.2", "d10845bc147b9f61ef485cbf0973c0a337237199bd9bd30dd9542db00aadc26b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0 or ~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_sql": {:hex, :ecto_sql, "3.2.2", "d10845bc147b9f61ef485cbf0973c0a337237199bd9bd30dd9542db00aadc26b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0 or ~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"}, "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"},
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"},

View file

@ -0,0 +1,17 @@
defmodule Pleroma.Repo.Migrations.CreateUserRelationships do
use Ecto.Migration
def change do
create_if_not_exists table(:user_relationships) do
add(:source_id, references(:users, type: :uuid, on_delete: :delete_all))
add(:target_id, references(:users, type: :uuid, on_delete: :delete_all))
add(:relationship_type, :integer, null: false)
timestamps(updated_at: false)
end
create_if_not_exists(
unique_index(:user_relationships, [:source_id, :relationship_type, :target_id])
)
end
end

View file

@ -0,0 +1,68 @@
defmodule Pleroma.Repo.Migrations.DataMigrationPopulateUserRelationships do
use Ecto.Migration
alias Ecto.Adapters.SQL
alias Pleroma.Repo
require Logger
def up do
Enum.each(
[blocks: 1, mutes: 2, muted_reblogs: 3, muted_notifications: 4, subscribers: 5],
fn {field, relationship_type_code} ->
migrate(field, relationship_type_code)
if field == :subscribers do
drop_if_exists(index(:users, [:subscribers]))
end
end
)
end
def down, do: :noop
defp migrate(field, relationship_type_code) do
Logger.info("Processing users.#{field}...")
{:ok, %{rows: field_rows}} =
SQL.query(Repo, "SELECT id, #{field} FROM users WHERE #{field} != '{}'")
target_ap_ids =
Enum.flat_map(
field_rows,
fn [_, ap_ids] -> ap_ids end
)
|> Enum.uniq()
# Selecting ids of all targets at once in order to reduce the number of SELECT queries
{:ok, %{rows: target_ap_id_id}} =
SQL.query(Repo, "SELECT ap_id, id FROM users WHERE ap_id = ANY($1)", [target_ap_ids])
target_id_by_ap_id = Enum.into(target_ap_id_id, %{}, fn [k, v] -> {k, v} end)
Enum.each(
field_rows,
fn [source_id, target_ap_ids] ->
source_uuid = Ecto.UUID.cast!(source_id)
for target_ap_id <- target_ap_ids do
target_id = target_id_by_ap_id[target_ap_id]
with {:ok, target_uuid} <- target_id && Ecto.UUID.cast(target_id) do
execute("""
INSERT INTO user_relationships(
source_id, target_id, relationship_type, inserted_at
)
VALUES(
'#{source_uuid}'::uuid, '#{target_uuid}'::uuid, #{relationship_type_code}, now()
)
ON CONFLICT (source_id, relationship_type, target_id) DO NOTHING
""")
else
_ -> Logger.warn("Unresolved #{field} reference: (#{source_uuid}, #{target_id})")
end
end
end
)
end
end

View file

@ -252,7 +252,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
assert User.get_cached_by_id(blocker.id).unread_conversation_count == 4 assert User.get_cached_by_id(blocker.id).unread_conversation_count == 4
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
# The conversations with the blocked user are marked as read # The conversations with the blocked user are marked as read
assert [%{read: true}, %{read: true}, %{read: true}, %{read: false}] = assert [%{read: true}, %{read: true}, %{read: true}, %{read: false}] =
@ -274,7 +274,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
blocked = insert(:user) blocked = insert(:user)
third_user = insert(:user) third_user = insert(:user)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
# When the blocked user is the author # When the blocked user is the author
{:ok, _direct1} = {:ok, _direct1} =
@ -311,7 +311,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
"visibility" => "direct" "visibility" => "direct"
}) })
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
assert [%{read: true}] = Participation.for_user(blocker) assert [%{read: true}] = Participation.for_user(blocker)
assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0 assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0

View file

@ -93,7 +93,7 @@ defmodule Pleroma.NotificationTest do
activity = insert(:note_activity) activity = insert(:note_activity)
author = User.get_cached_by_ap_id(activity.data["actor"]) author = User.get_cached_by_ap_id(activity.data["actor"])
user = insert(:user) user = insert(:user)
{:ok, user} = User.block(user, author) {:ok, _user_relationship} = User.block(user, author)
assert Notification.create_notification(activity, user) assert Notification.create_notification(activity, user)
end end
@ -112,7 +112,7 @@ defmodule Pleroma.NotificationTest do
muter = insert(:user) muter = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, muter} = User.mute(muter, muted, false) {:ok, _user_relationships} = User.mute(muter, muted, false)
{:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"}) {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"})
@ -643,13 +643,7 @@ defmodule Pleroma.NotificationTest do
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user) Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
ObanHelpers.perform_all() ObanHelpers.perform_all()
assert [ assert [] = Notification.for_user(follower)
%{
activity: %{
data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
}
}
] = Notification.for_user(follower)
assert [ assert [
%{ %{
@ -657,7 +651,17 @@ defmodule Pleroma.NotificationTest do
data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id} data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
} }
} }
] = Notification.for_user(other_follower) ] = Notification.for_user(follower, %{with_move: true})
assert [] = Notification.for_user(other_follower)
assert [
%{
activity: %{
data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
}
}
] = Notification.for_user(other_follower, %{with_move: true})
end end
end end
@ -665,7 +669,7 @@ defmodule Pleroma.NotificationTest do
test "it returns notifications for muted user without notifications" do test "it returns notifications for muted user without notifications" do
user = insert(:user) user = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, user} = User.mute(user, muted, false) {:ok, _user_relationships} = User.mute(user, muted, false)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"}) {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
@ -675,7 +679,7 @@ defmodule Pleroma.NotificationTest do
test "it doesn't return notifications for muted user with notifications" do test "it doesn't return notifications for muted user with notifications" do
user = insert(:user) user = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, user} = User.mute(user, muted) {:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"}) {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
@ -685,7 +689,7 @@ defmodule Pleroma.NotificationTest do
test "it doesn't return notifications for blocked user" do test "it doesn't return notifications for blocked user" do
user = insert(:user) user = insert(:user)
blocked = insert(:user) blocked = insert(:user)
{:ok, user} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
@ -715,7 +719,7 @@ defmodule Pleroma.NotificationTest do
test "it returns notifications from a muted user when with_muted is set" do test "it returns notifications from a muted user when with_muted is set" do
user = insert(:user) user = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, user} = User.mute(user, muted) {:ok, _user_relationships} = User.mute(user, muted)
{:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"}) {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
@ -725,7 +729,7 @@ defmodule Pleroma.NotificationTest do
test "it doesn't return notifications from a blocked user when with_muted is set" do test "it doesn't return notifications from a blocked user when with_muted is set" do
user = insert(:user) user = insert(:user)
blocked = insert(:user) blocked = insert(:user)
{:ok, user} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"}) {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})

View file

@ -23,6 +23,7 @@ defmodule Pleroma.Web.ChannelCase do
quote do quote do
# Import conveniences for testing with channels # Import conveniences for testing with channels
use Phoenix.ChannelTest use Phoenix.ChannelTest
use Pleroma.Tests.Helpers
# The default endpoint for testing # The default endpoint for testing
@endpoint Pleroma.Web.Endpoint @endpoint Pleroma.Web.Endpoint

View file

@ -42,6 +42,18 @@ defmodule Pleroma.Factory do
} }
end end
def user_relationship_factory(attrs \\ %{}) do
source = attrs[:source] || insert(:user)
target = attrs[:target] || insert(:user)
relationship_type = attrs[:relationship_type] || :block
%Pleroma.UserRelationship{
source_id: source.id,
target_id: target.id,
relationship_type: relationship_type
}
end
def note_factory(attrs \\ %{}) do def note_factory(attrs \\ %{}) do
text = sequence(:text, &"This is :moominmamma: note #{&1}") text = sequence(:text, &"This is :moominmamma: note #{&1}")

View file

@ -81,6 +81,23 @@ defmodule Pleroma.Tests.Helpers do
|> Poison.decode!() |> Poison.decode!()
end end
def stringify_keys(nil), do: nil
def stringify_keys(key) when key in [true, false], do: key
def stringify_keys(key) when is_atom(key), do: Atom.to_string(key)
def stringify_keys(map) when is_map(map) do
map
|> Enum.map(fn {k, v} -> {stringify_keys(k), stringify_keys(v)} end)
|> Enum.into(%{})
end
def stringify_keys([head | rest] = list) when is_list(list) do
[stringify_keys(head) | stringify_keys(rest)]
end
def stringify_keys(key), do: key
defmacro guards_config(config_path) do defmacro guards_config(config_path) do
quote do quote do
initial_setting = Pleroma.Config.get(config_path) initial_setting = Pleroma.Config.get(config_path)

View file

@ -0,0 +1,130 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserRelationshipTest do
alias Pleroma.UserRelationship
use Pleroma.DataCase
import Pleroma.Factory
describe "*_exists?/2" do
setup do
{:ok, users: insert_list(2, :user)}
end
test "returns false if record doesn't exist", %{users: [user1, user2]} do
refute UserRelationship.block_exists?(user1, user2)
refute UserRelationship.mute_exists?(user1, user2)
refute UserRelationship.notification_mute_exists?(user1, user2)
refute UserRelationship.reblog_mute_exists?(user1, user2)
refute UserRelationship.inverse_subscription_exists?(user1, user2)
end
test "returns true if record exists", %{users: [user1, user2]} do
for relationship_type <- [
:block,
:mute,
:notification_mute,
:reblog_mute,
:inverse_subscription
] do
insert(:user_relationship,
source: user1,
target: user2,
relationship_type: relationship_type
)
end
assert UserRelationship.block_exists?(user1, user2)
assert UserRelationship.mute_exists?(user1, user2)
assert UserRelationship.notification_mute_exists?(user1, user2)
assert UserRelationship.reblog_mute_exists?(user1, user2)
assert UserRelationship.inverse_subscription_exists?(user1, user2)
end
end
describe "create_*/2" do
setup do
{:ok, users: insert_list(2, :user)}
end
test "creates user relationship record if it doesn't exist", %{users: [user1, user2]} do
for relationship_type <- [
:block,
:mute,
:notification_mute,
:reblog_mute,
:inverse_subscription
] do
insert(:user_relationship,
source: user1,
target: user2,
relationship_type: relationship_type
)
end
UserRelationship.create_block(user1, user2)
UserRelationship.create_mute(user1, user2)
UserRelationship.create_notification_mute(user1, user2)
UserRelationship.create_reblog_mute(user1, user2)
UserRelationship.create_inverse_subscription(user1, user2)
assert UserRelationship.block_exists?(user1, user2)
assert UserRelationship.mute_exists?(user1, user2)
assert UserRelationship.notification_mute_exists?(user1, user2)
assert UserRelationship.reblog_mute_exists?(user1, user2)
assert UserRelationship.inverse_subscription_exists?(user1, user2)
end
test "if record already exists, returns it", %{users: [user1, user2]} do
user_block = UserRelationship.create_block(user1, user2)
assert user_block == UserRelationship.create_block(user1, user2)
end
end
describe "delete_*/2" do
setup do
{:ok, users: insert_list(2, :user)}
end
test "deletes user relationship record if it exists", %{users: [user1, user2]} do
for relationship_type <- [
:block,
:mute,
:notification_mute,
:reblog_mute,
:inverse_subscription
] do
insert(:user_relationship,
source: user1,
target: user2,
relationship_type: relationship_type
)
end
assert {:ok, %UserRelationship{}} = UserRelationship.delete_block(user1, user2)
assert {:ok, %UserRelationship{}} = UserRelationship.delete_mute(user1, user2)
assert {:ok, %UserRelationship{}} = UserRelationship.delete_notification_mute(user1, user2)
assert {:ok, %UserRelationship{}} = UserRelationship.delete_reblog_mute(user1, user2)
assert {:ok, %UserRelationship{}} =
UserRelationship.delete_inverse_subscription(user1, user2)
refute UserRelationship.block_exists?(user1, user2)
refute UserRelationship.mute_exists?(user1, user2)
refute UserRelationship.notification_mute_exists?(user1, user2)
refute UserRelationship.reblog_mute_exists?(user1, user2)
refute UserRelationship.inverse_subscription_exists?(user1, user2)
end
test "if record does not exist, returns {:ok, nil}", %{users: [user1, user2]} do
assert {:ok, nil} = UserRelationship.delete_block(user1, user2)
assert {:ok, nil} = UserRelationship.delete_mute(user1, user2)
assert {:ok, nil} = UserRelationship.delete_notification_mute(user1, user2)
assert {:ok, nil} = UserRelationship.delete_reblog_mute(user1, user2)
assert {:ok, nil} = UserRelationship.delete_inverse_subscription(user1, user2)
end
end
end

View file

@ -44,6 +44,56 @@ defmodule Pleroma.UserTest do
end end
end end
describe "AP ID user relationships" do
setup do
{:ok, user: insert(:user)}
end
test "outgoing_relations_ap_ids/1", %{user: user} do
rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
ap_ids_by_rel =
Enum.into(
rel_types,
%{},
fn rel_type ->
rel_records =
insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
{rel_type, Enum.sort(ap_ids)}
end
)
assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
assert ap_ids_by_rel[:notification_mute] ==
Enum.sort(User.notification_muted_users_ap_ids(user))
assert ap_ids_by_rel[:notification_mute] ==
Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
assert ap_ids_by_rel[:reblog_mute] ==
Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
assert ap_ids_by_rel[:inverse_subscription] ==
Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
outgoing_relations_ap_ids = User.outgoing_relations_ap_ids(user, rel_types)
assert ap_ids_by_rel ==
Enum.into(outgoing_relations_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
end
end
describe "when tags are nil" do describe "when tags are nil" do
test "tagging a user" do test "tagging a user" do
user = insert(:user, %{tags: nil}) user = insert(:user, %{tags: nil})
@ -119,7 +169,7 @@ defmodule Pleroma.UserTest do
CommonAPI.follow(follower, followed) CommonAPI.follow(follower, followed)
assert [_activity] = User.get_follow_requests(followed) assert [_activity] = User.get_follow_requests(followed)
{:ok, _follower} = User.block(followed, follower) {:ok, _user_relationship} = User.block(followed, follower)
assert [] = User.get_follow_requests(followed) assert [] = User.get_follow_requests(followed)
end end
@ -132,8 +182,8 @@ defmodule Pleroma.UserTest do
not_followed = insert(:user) not_followed = insert(:user)
reverse_blocked = insert(:user) reverse_blocked = insert(:user)
{:ok, user} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
{:ok, reverse_blocked} = User.block(reverse_blocked, user) {:ok, _user_relationship} = User.block(reverse_blocked, user)
{:ok, user} = User.follow(user, followed_zero) {:ok, user} = User.follow(user, followed_zero)
@ -186,7 +236,7 @@ defmodule Pleroma.UserTest do
blocker = insert(:user) blocker = insert(:user)
blockee = insert(:user) blockee = insert(:user)
{:ok, blocker} = User.block(blocker, blockee) {:ok, _user_relationship} = User.block(blocker, blockee)
{:error, _} = User.follow(blockee, blocker) {:error, _} = User.follow(blockee, blocker)
end end
@ -195,7 +245,7 @@ defmodule Pleroma.UserTest do
blocker = insert(:user) blocker = insert(:user)
blocked = insert(:user) blocked = insert(:user)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
{:error, _} = User.subscribe(blocked, blocker) {:error, _} = User.subscribe(blocked, blocker)
end end
@ -678,7 +728,7 @@ defmodule Pleroma.UserTest do
refute User.mutes?(user, muted_user) refute User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user) refute User.muted_notifications?(user, muted_user)
{:ok, user} = User.mute(user, muted_user) {:ok, _user_relationships} = User.mute(user, muted_user)
assert User.mutes?(user, muted_user) assert User.mutes?(user, muted_user)
assert User.muted_notifications?(user, muted_user) assert User.muted_notifications?(user, muted_user)
@ -688,8 +738,8 @@ defmodule Pleroma.UserTest do
user = insert(:user) user = insert(:user)
muted_user = insert(:user) muted_user = insert(:user)
{:ok, user} = User.mute(user, muted_user) {:ok, _user_relationships} = User.mute(user, muted_user)
{:ok, user} = User.unmute(user, muted_user) {:ok, _user_mute} = User.unmute(user, muted_user)
refute User.mutes?(user, muted_user) refute User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user) refute User.muted_notifications?(user, muted_user)
@ -702,7 +752,7 @@ defmodule Pleroma.UserTest do
refute User.mutes?(user, muted_user) refute User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user) refute User.muted_notifications?(user, muted_user)
{:ok, user} = User.mute(user, muted_user, false) {:ok, _user_relationships} = User.mute(user, muted_user, false)
assert User.mutes?(user, muted_user) assert User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user) refute User.muted_notifications?(user, muted_user)
@ -716,7 +766,7 @@ defmodule Pleroma.UserTest do
refute User.blocks?(user, blocked_user) refute User.blocks?(user, blocked_user)
{:ok, user} = User.block(user, blocked_user) {:ok, _user_relationship} = User.block(user, blocked_user)
assert User.blocks?(user, blocked_user) assert User.blocks?(user, blocked_user)
end end
@ -725,8 +775,8 @@ defmodule Pleroma.UserTest do
user = insert(:user) user = insert(:user)
blocked_user = insert(:user) blocked_user = insert(:user)
{:ok, user} = User.block(user, blocked_user) {:ok, _user_relationship} = User.block(user, blocked_user)
{:ok, user} = User.unblock(user, blocked_user) {:ok, _user_block} = User.unblock(user, blocked_user)
refute User.blocks?(user, blocked_user) refute User.blocks?(user, blocked_user)
end end
@ -741,7 +791,7 @@ defmodule Pleroma.UserTest do
assert User.following?(blocker, blocked) assert User.following?(blocker, blocked)
assert User.following?(blocked, blocker) assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
blocked = User.get_cached_by_id(blocked.id) blocked = User.get_cached_by_id(blocked.id)
assert User.blocks?(blocker, blocked) assert User.blocks?(blocker, blocked)
@ -759,7 +809,7 @@ defmodule Pleroma.UserTest do
assert User.following?(blocker, blocked) assert User.following?(blocker, blocked)
refute User.following?(blocked, blocker) refute User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
blocked = User.get_cached_by_id(blocked.id) blocked = User.get_cached_by_id(blocked.id)
assert User.blocks?(blocker, blocked) assert User.blocks?(blocker, blocked)
@ -777,7 +827,7 @@ defmodule Pleroma.UserTest do
refute User.following?(blocker, blocked) refute User.following?(blocker, blocked)
assert User.following?(blocked, blocker) assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
blocked = User.get_cached_by_id(blocked.id) blocked = User.get_cached_by_id(blocked.id)
assert User.blocks?(blocker, blocked) assert User.blocks?(blocker, blocked)
@ -790,12 +840,12 @@ defmodule Pleroma.UserTest do
blocker = insert(:user) blocker = insert(:user)
blocked = insert(:user) blocked = insert(:user)
{:ok, blocker} = User.subscribe(blocked, blocker) {:ok, _subscription} = User.subscribe(blocked, blocker)
assert User.subscribed_to?(blocked, blocker) assert User.subscribed_to?(blocked, blocker)
refute User.subscribed_to?(blocker, blocked) refute User.subscribed_to?(blocker, blocked)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
assert User.blocks?(blocker, blocked) assert User.blocks?(blocker, blocked)
refute User.subscribed_to?(blocker, blocked) refute User.subscribed_to?(blocker, blocked)
@ -1324,7 +1374,8 @@ defmodule Pleroma.UserTest do
{:ok, _follower2} = User.follow(follower2, user) {:ok, _follower2} = User.follow(follower2, user)
{:ok, _follower3} = User.follow(follower3, user) {:ok, _follower3} = User.follow(follower3, user)
{:ok, user} = User.block(user, follower) {:ok, _user_relationship} = User.block(user, follower)
user = refresh_record(user)
assert user.follower_count == 2 assert user.follower_count == 2
end end

View file

@ -298,7 +298,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert json_response(conn1, :ok) assert json_response(conn1, :ok)
assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"})) assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
Activity.delete_by_ap_id(activity.object.data["id"]) Activity.delete_all_by_object_ap_id(activity.object.data["id"])
conn2 = conn2 =
conn conn

View file

@ -487,7 +487,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_five = insert(:note_activity) activity_five = insert(:note_activity)
user = insert(:user) user = insert(:user)
{:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]}) {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]})
activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user}) activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
assert activities == [activity_two, activity] assert activities == [activity_two, activity]
@ -500,7 +500,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_three = insert(:note_activity) activity_three = insert(:note_activity)
user = insert(:user) user = insert(:user)
booster = insert(:user) booster = insert(:user)
{:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]}) {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]})
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@ -509,7 +509,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
refute Enum.member?(activities, activity_one) refute Enum.member?(activities, activity_one)
{:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@ -518,7 +518,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)
{:ok, user} = 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, _announce, %{data: %{"id" => 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)
@ -545,7 +545,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
blockee = insert(:user) blockee = insert(:user)
friend = insert(:user) friend = insert(:user)
{:ok, blocker} = User.block(blocker, blockee) {:ok, _user_relationship} = User.block(blocker, blockee)
{:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"}) {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
@ -568,7 +568,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
blockee = insert(:user) blockee = insert(:user)
friend = insert(:user) friend = insert(:user)
{:ok, blocker} = User.block(blocker, blockee) {:ok, _user_relationship} = User.block(blocker, blockee)
{:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"}) {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
@ -614,7 +614,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_three = insert(:note_activity) activity_three = insert(:note_activity)
user = insert(:user) user = insert(:user)
booster = insert(:user) booster = insert(:user)
{:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})
activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
{:ok, _user_relationships} = User.mute(user, activity_one_actor)
activities = activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@ -635,7 +637,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)
{:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]}) {:ok, _user_mute} = User.unmute(user, activity_one_actor)
activities = activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@ -644,7 +646,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three) assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)
{:ok, user} = User.mute(user, %User{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, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) {:ok, _announce, %{data: %{"id" => 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)
@ -791,7 +794,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity = insert(:note_activity) activity = insert(:note_activity)
user = insert(:user) user = insert(:user)
booster = insert(:user) booster = insert(:user)
{:ok, user} = 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)
@ -804,8 +807,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity = insert(:note_activity) activity = insert(:note_activity)
user = insert(:user) user = insert(:user)
booster = insert(:user) booster = insert(:user)
{:ok, user} = CommonAPI.hide_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, user} = 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)
@ -1256,6 +1259,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 0 assert object.data["repliesCount"] == 0
end end
test "it passes delete activity through MRF before deleting the object" do
rewrite_policy = Pleroma.Config.get([:instance, :rewrite_policy])
Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy)
on_exit(fn -> Pleroma.Config.put([:instance, :rewrite_policy], rewrite_policy) end)
note = insert(:note_activity)
object = Object.normalize(note)
{:error, {:reject, _}} = ActivityPub.delete(object)
assert Activity.get_by_id(note.id)
assert Repo.get(Object, object.id).data["type"] == object.data["type"]
end
end end
describe "timeline post-processing" do describe "timeline post-processing" do
@ -1619,10 +1637,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity = %Activity{activity | object: nil} activity = %Activity{activity | object: nil}
assert [%Notification{activity: ^activity}] = assert [%Notification{activity: ^activity}] =
Notification.for_user_since(follower, ~N[2019-04-13 11:22:33]) Notification.for_user(follower, %{with_move: true})
assert [%Notification{activity: ^activity}] = assert [%Notification{activity: ^activity}] =
Notification.for_user_since(follower_move_opted_out, ~N[2019-04-13 11:22:33]) Notification.for_user(follower_move_opted_out, %{with_move: true})
end end
test "old user must be in the new user's `also_known_as` list" do test "old user must be in the new user's `also_known_as` list" do

View file

@ -128,7 +128,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
user = insert(:user) user = insert(:user)
{:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin") {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
{:ok, user} = User.block(user, target) {:ok, _user_relationship} = User.block(user, target)
data = data =
File.read!("test/fixtures/mastodon-follow-activity.json") File.read!("test/fixtures/mastodon-follow-activity.json")

View file

@ -636,47 +636,4 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
assert updated_object.data["announcement_count"] == 1 assert updated_object.data["announcement_count"] == 1
end end
end end
describe "get_reports_grouped_by_status/1" do
setup do
[reporter, target_user] = insert_pair(:user)
first_status = insert(:note_activity, user: target_user)
second_status = insert(:note_activity, user: target_user)
CommonAPI.report(reporter, %{
"account_id" => target_user.id,
"comment" => "I feel offended",
"status_ids" => [first_status.id]
})
CommonAPI.report(reporter, %{
"account_id" => target_user.id,
"comment" => "I feel offended2",
"status_ids" => [second_status.id]
})
data = [%{activity: first_status.data["id"]}, %{activity: second_status.data["id"]}]
{:ok,
%{
first_status: first_status,
second_status: second_status,
data: data
}}
end
test "works for deprecated reports format", %{
first_status: first_status,
second_status: second_status,
data: data
} do
groups = Utils.get_reports_grouped_by_status(data).groups
first_group = Enum.find(groups, &(&1.status.id == first_status.data["id"]))
second_group = Enum.find(groups, &(&1.status.id == second_status.data["id"]))
assert first_group.status.id == first_status.data["id"]
assert second_group.status.id == second_status.data["id"]
end
end
end end

View file

@ -15,6 +15,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
alias Pleroma.UserInviteToken alias Pleroma.UserInviteToken
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
import Pleroma.Factory import Pleroma.Factory
@ -1612,6 +1613,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]), first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]), second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]), third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
first_report: first_report,
first_status_reports: [first_report, second_report, third_report], first_status_reports: [first_report, second_report, third_report],
second_status_reports: [first_report, second_report], second_status_reports: [first_report, second_report],
third_status_reports: [first_report], third_status_reports: [first_report],
@ -1638,14 +1640,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert length(response["reports"]) == 3 assert length(response["reports"]) == 3
first_group = first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
Enum.find(response["reports"], &(&1["status"]["id"] == first_status.data["id"]))
second_group = second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
Enum.find(response["reports"], &(&1["status"]["id"] == second_status.data["id"]))
third_group = third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
Enum.find(response["reports"], &(&1["status"]["id"] == third_status.data["id"]))
assert length(first_group["reports"]) == 3 assert length(first_group["reports"]) == 3
assert length(second_group["reports"]) == 2 assert length(second_group["reports"]) == 2
@ -1656,13 +1655,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
NaiveDateTime.from_iso8601!(act.data["published"]) NaiveDateTime.from_iso8601!(act.data["published"])
end).data["published"] end).data["published"]
assert first_group["status"] == %{ assert first_group["status"] ==
"id" => first_status.data["id"], Map.put(
"content" => first_status.object.data["content"], stringify_keys(StatusView.render("show.json", %{activity: first_status})),
"published" => first_status.object.data["published"] "deleted",
} false
)
assert first_group["account"]["id"] == target_user.id assert(first_group["account"]["id"] == target_user.id)
assert length(first_group["actors"]) == 1 assert length(first_group["actors"]) == 1
assert hd(first_group["actors"])["id"] == reporter.id assert hd(first_group["actors"])["id"] == reporter.id
@ -1675,11 +1675,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
NaiveDateTime.from_iso8601!(act.data["published"]) NaiveDateTime.from_iso8601!(act.data["published"])
end).data["published"] end).data["published"]
assert second_group["status"] == %{ assert second_group["status"] ==
"id" => second_status.data["id"], Map.put(
"content" => second_status.object.data["content"], stringify_keys(StatusView.render("show.json", %{activity: second_status})),
"published" => second_status.object.data["published"] "deleted",
} false
)
assert second_group["account"]["id"] == target_user.id assert second_group["account"]["id"] == target_user.id
@ -1694,11 +1695,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
NaiveDateTime.from_iso8601!(act.data["published"]) NaiveDateTime.from_iso8601!(act.data["published"])
end).data["published"] end).data["published"]
assert third_group["status"] == %{ assert third_group["status"] ==
"id" => third_status.data["id"], Map.put(
"content" => third_status.object.data["content"], stringify_keys(StatusView.render("show.json", %{activity: third_status})),
"published" => third_status.object.data["published"] "deleted",
} false
)
assert third_group["account"]["id"] == target_user.id assert third_group["account"]["id"] == target_user.id
@ -1708,6 +1710,70 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert Enum.map(third_group["reports"], & &1["id"]) -- assert Enum.map(third_group["reports"], & &1["id"]) --
Enum.map(third_status_reports, & &1.id) == [] Enum.map(third_status_reports, & &1.id) == []
end end
test "reopened report renders status data", %{
conn: conn,
first_report: first_report,
first_status: first_status
} do
{:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
response =
conn
|> get("/api/pleroma/admin/grouped_reports")
|> json_response(:ok)
first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
assert first_group["status"] ==
Map.put(
stringify_keys(StatusView.render("show.json", %{activity: first_status})),
"deleted",
false
)
end
test "reopened report does not render status data if status has been deleted", %{
conn: conn,
first_report: first_report,
first_status: first_status,
target_user: target_user
} do
{:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
{:ok, _} = CommonAPI.delete(first_status.id, target_user)
refute Activity.get_by_ap_id(first_status.id)
response =
conn
|> get("/api/pleroma/admin/grouped_reports")
|> json_response(:ok)
assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
"deleted"
] == true
assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
end
test "account not empty if status was deleted", %{
conn: conn,
first_report: first_report,
first_status: first_status,
target_user: target_user
} do
{:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
{:ok, _} = CommonAPI.delete(first_status.id, target_user)
refute Activity.get_by_ap_id(first_status.id)
response =
conn
|> get("/api/pleroma/admin/grouped_reports")
|> json_response(:ok)
assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
end
end end
describe "POST /api/pleroma/admin/reports/:id/respond" do describe "POST /api/pleroma/admin/reports/:id/respond" do

View file

@ -0,0 +1,37 @@
defmodule Pleroma.Web.ChatChannelTest do
use Pleroma.Web.ChannelCase
alias Pleroma.Web.ChatChannel
alias Pleroma.Web.UserSocket
import Pleroma.Factory
setup do
user = insert(:user)
{:ok, _, socket} =
socket(UserSocket, "", %{user_name: user.nickname})
|> subscribe_and_join(ChatChannel, "chat:public")
{:ok, socket: socket}
end
test "it broadcasts a message", %{socket: socket} do
push(socket, "new_msg", %{"text" => "why is tenshi eating a corndog so cute?"})
assert_broadcast("new_msg", %{text: "why is tenshi eating a corndog so cute?"})
end
describe "message lengths" do
clear_config([:instance, :chat_limit])
test "it ignores messages of length zero", %{socket: socket} do
push(socket, "new_msg", %{"text" => ""})
refute_broadcast("new_msg", %{text: ""})
end
test "it ignores messages above a certain length", %{socket: socket} do
Pleroma.Config.put([:instance, :chat_limit], 2)
push(socket, "new_msg", %{"text" => "123"})
refute_broadcast("new_msg", %{text: "123"})
end
end
end

View file

@ -509,14 +509,14 @@ defmodule Pleroma.Web.CommonAPITest do
end end
test "add a reblog mute", %{muter: muter, muted: muted} do test "add a reblog mute", %{muter: muter, muted: muted} do
{:ok, muter} = CommonAPI.hide_reblogs(muter, muted) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
assert User.showing_reblogs?(muter, muted) == false assert User.showing_reblogs?(muter, muted) == false
end end
test "remove a reblog mute", %{muter: muter, muted: muted} do test "remove a reblog mute", %{muter: muter, muted: muted} do
{:ok, muter} = CommonAPI.hide_reblogs(muter, muted) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
{:ok, muter} = CommonAPI.show_reblogs(muter, muted) {:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
assert User.showing_reblogs?(muter, muted) == true assert User.showing_reblogs?(muter, muted) == true
end end
@ -526,7 +526,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "also unsubscribes a user" do test "also unsubscribes a user" do
[follower, followed] = insert_pair(:user) [follower, followed] = insert_pair(:user)
{:ok, follower, followed, _} = CommonAPI.follow(follower, followed) {:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
{:ok, followed} = User.subscribe(follower, followed) {:ok, _subscription} = User.subscribe(follower, followed)
assert User.subscribed_to?(follower, followed) assert User.subscribed_to?(follower, followed)

View file

@ -144,6 +144,50 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
end end
describe "user timelines" do describe "user timelines" do
test "respects blocks", %{conn: conn} do
user_one = insert(:user)
user_two = insert(:user)
user_three = insert(:user)
User.block(user_one, user_two)
{:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
{:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
resp =
conn
|> get("/api/v1/accounts/#{user_two.id}/statuses")
assert [%{"id" => id}] = json_response(resp, 200)
assert id == activity.id
# Even a blocked user will deliver the full user timeline, there would be
# no point in looking at a blocked users timeline otherwise
resp =
conn
|> assign(:user, user_one)
|> get("/api/v1/accounts/#{user_two.id}/statuses")
assert [%{"id" => id}] = json_response(resp, 200)
assert id == activity.id
resp =
conn
|> get("/api/v1/accounts/#{user_three.id}/statuses")
assert [%{"id" => id}] = json_response(resp, 200)
assert id == repeat.id
# When viewing a third user's timeline, the blocked users will NOT be
# shown.
resp =
conn
|> assign(:user, user_one)
|> get("/api/v1/accounts/#{user_three.id}/statuses")
assert [] = json_response(resp, 200)
end
test "gets a users statuses", %{conn: conn} do test "gets a users statuses", %{conn: conn} do
user_one = insert(:user) user_one = insert(:user)
user_two = insert(:user) user_two = insert(:user)
@ -891,7 +935,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.mute(user, other_user) {:ok, _user_relationships} = User.mute(user, other_user)
conn = conn =
conn conn
@ -906,7 +950,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.block(user, other_user) {:ok, _user_relationship} = User.block(user, other_user)
conn = conn =
conn conn

View file

@ -289,7 +289,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response(conn, 200)) == 1 assert length(json_response(conn, 200)) == 1
{:ok, user} = User.mute(user, user2) {:ok, _user_relationships} = User.mute(user, user2)
conn = assign(build_conn(), :user, user) conn = assign(build_conn(), :user, user)
conn = get(conn, "/api/v1/notifications") conn = get(conn, "/api/v1/notifications")
@ -310,7 +310,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response(conn, 200)) == 1 assert length(json_response(conn, 200)) == 1
{:ok, user} = User.mute(user, user2, false) {:ok, _user_relationships} = User.mute(user, user2, false)
conn = assign(build_conn(), :user, user) conn = assign(build_conn(), :user, user)
conn = get(conn, "/api/v1/notifications") conn = get(conn, "/api/v1/notifications")
@ -333,7 +333,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response(conn, 200)) == 1 assert length(json_response(conn, 200)) == 1
{:ok, user} = User.mute(user, user2) {:ok, _user_relationships} = User.mute(user, user2)
conn = assign(build_conn(), :user, user) conn = assign(build_conn(), :user, user)
conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"}) conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
@ -341,6 +341,32 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response(conn, 200)) == 1 assert length(json_response(conn, 200)) == 1
end end
test "see move notifications with `with_move` parameter", %{
conn: conn
} do
old_user = insert(:user)
new_user = insert(:user, also_known_as: [old_user.ap_id])
follower = insert(:user)
User.follow(follower, old_user)
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
Pleroma.Tests.ObanHelpers.perform_all()
conn =
conn
|> assign(:user, follower)
|> get("/api/v1/notifications")
assert json_response(conn, 200) == []
conn =
build_conn()
|> assign(:user, follower)
|> get("/api/v1/notifications", %{"with_move" => "true"})
assert length(json_response(conn, 200)) == 1
end
defp get_notification_id_by_activity(%{id: id}) do defp get_notification_id_by_activity(%{id: id}) do
Notification Notification
|> Repo.get_by(activity_id: id) |> Repo.get_by(activity_id: id)

View file

@ -1108,7 +1108,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
activity: activity activity: activity
} do } do
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.block(user, other_user) {:ok, _user_relationship} = User.block(user, other_user)
{:ok, _, _} = CommonAPI.favorite(activity.id, other_user) {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
@ -1205,7 +1205,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
activity: activity activity: activity
} do } do
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = 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)

View file

@ -194,7 +194,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
blocker = insert(:user) blocker = insert(:user)
blocked = insert(:user) blocked = insert(:user)
user = insert(:user) user = insert(:user)
{:ok, blocker} = User.block(blocker, blocked) {:ok, _user_relationship} = User.block(blocker, blocked)
{:ok, _blocked_direct} = {:ok, _blocked_direct} =
CommonAPI.post(blocked, %{ CommonAPI.post(blocked, %{

View file

@ -190,9 +190,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
{:ok, user} = User.follow(user, other_user) {:ok, user} = User.follow(user, other_user)
{:ok, other_user} = User.follow(other_user, user) {:ok, other_user} = User.follow(other_user, user)
{:ok, other_user} = User.subscribe(user, other_user) {:ok, _subscription} = User.subscribe(user, other_user)
{:ok, user} = User.mute(user, other_user, true) {:ok, _user_relationships} = User.mute(user, other_user, true)
{:ok, user} = CommonAPI.hide_reblogs(user, other_user) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, other_user)
expected = %{ expected = %{
id: to_string(other_user.id), id: to_string(other_user.id),
@ -218,9 +218,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.follow(user, other_user) {:ok, user} = User.follow(user, other_user)
{:ok, other_user} = User.subscribe(user, other_user) {:ok, _subscription} = User.subscribe(user, other_user)
{:ok, user} = User.block(user, other_user) {:ok, _user_relationship} = User.block(user, other_user)
{:ok, other_user} = User.block(other_user, user) {:ok, _user_relationship} = User.block(other_user, user)
expected = %{ expected = %{
id: to_string(other_user.id), id: to_string(other_user.id),
@ -291,7 +291,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, other_user} = User.follow(other_user, user) {:ok, other_user} = User.follow(other_user, user)
{:ok, other_user} = User.block(other_user, user) {:ok, _user_relationship} = User.block(other_user, user)
{:ok, _} = User.follow(insert(:user), user) {:ok, _} = User.follow(insert(:user), user)
expected = %{ expected = %{

View file

@ -109,8 +109,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
end end
test "Move notification" do test "Move notification" do
%{ap_id: old_ap_id} = old_user = insert(:user) old_user = insert(:user)
%{ap_id: _new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id]) new_user = insert(:user, also_known_as: [old_user.ap_id])
follower = insert(:user) follower = insert(:user)
User.follow(follower, old_user) User.follow(follower, old_user)
@ -120,7 +120,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
old_user = refresh_record(old_user) old_user = refresh_record(old_user)
new_user = refresh_record(new_user) new_user = refresh_record(new_user)
[notification] = Notification.for_user(follower) [notification] = Notification.for_user(follower, %{with_move: true})
expected = %{ expected = %{
id: to_string(notification.id), id: to_string(notification.id),

View file

@ -183,7 +183,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.mute(user, other_user) {:ok, _user_relationships} = User.mute(user, other_user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
status = StatusView.render("show.json", %{activity: activity}) status = StatusView.render("show.json", %{activity: activity})
@ -199,7 +199,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, user} = User.mute(user, other_user) {:ok, _user_relationships} = User.mute(user, other_user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"}) {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
status = StatusView.render("show.json", %{activity: activity, for: user}) status = StatusView.render("show.json", %{activity: activity, for: user})

View file

@ -59,7 +59,7 @@ defmodule Pleroma.Web.StreamerTest do
user: user user: user
} do } do
blocked = insert(:user) blocked = insert(:user)
{:ok, user} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
task = Task.async(fn -> refute_receive {:text, _}, 4_000 end) task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
@ -259,7 +259,7 @@ defmodule Pleroma.Web.StreamerTest do
test "it doesn't send messages involving blocked users" do test "it doesn't send messages involving blocked users" do
user = insert(:user) user = insert(:user)
blocked_user = insert(:user) blocked_user = insert(:user)
{:ok, user} = User.block(user, blocked_user) {:ok, _user_relationship} = User.block(user, blocked_user)
task = task =
Task.async(fn -> Task.async(fn ->
@ -301,7 +301,7 @@ defmodule Pleroma.Web.StreamerTest do
"public" => [fake_socket] "public" => [fake_socket]
} }
{:ok, blocker} = User.block(blocker, blockee) {:ok, _user_relationship} = User.block(blocker, blockee)
{:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"}) {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"})

View file

@ -387,7 +387,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user = insert(:user) user = insert(:user)
user2 = insert(:user) user2 = insert(:user)
{:ok, _user} = Pleroma.User.block(user2, user) {:ok, _user_block} = Pleroma.User.block(user2, user)
response = response =
conn conn
@ -485,7 +485,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
Pleroma.Config.put([:user, :deny_follow_blocked], true) Pleroma.Config.put([:user, :deny_follow_blocked], true)
user = insert(:user) user = insert(:user)
user2 = insert(:user) user2 = insert(:user)
{:ok, _user} = Pleroma.User.block(user2, user) {:ok, _user_block} = Pleroma.User.block(user2, user)
response = response =
conn conn