forked from AkkomaGang/akkoma
Merge branch 'develop' into features/remove-user-source_data
This commit is contained in:
commit
942d7467ca
64 changed files with 857 additions and 403 deletions
54
CHANGELOG.md
54
CHANGELOG.md
|
@ -4,9 +4,6 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
### Changed
|
|
||||||
- **Breaking:** BBCode and Markdown formatters will no longer return any `\n` and only use `<br/>` for newlines
|
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- **Breaking:** removed `with_move` parameter from notifications timeline.
|
- **Breaking:** removed `with_move` parameter from notifications timeline.
|
||||||
|
|
||||||
|
@ -21,9 +18,58 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
|
- Mastodon API: Added `/api/v1/notifications/:id/dismiss` endpoint.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Support pagination in conversations API
|
||||||
|
|
||||||
|
## [unreleased-patch]
|
||||||
|
### Fixed
|
||||||
|
- Logger configuration through AdminFE
|
||||||
|
|
||||||
|
## [2.0.2] - 2020-04-08
|
||||||
|
### Added
|
||||||
|
- Support for Funkwhale's `Audio` activity
|
||||||
|
- Admin API: `PATCH /api/pleroma/admin/users/:nickname/update_credentials`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Blocked/muted users still generating push notifications
|
||||||
|
- Input textbox for bio ignoring newlines
|
||||||
|
- OTP: Inability to use PostgreSQL databases with SSL
|
||||||
|
- `user delete_activities` breaking when trying to delete already deleted posts
|
||||||
|
- Incorrect URL for Funkwhale channels
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
|
## [2.0.1] - 2020-03-15
|
||||||
|
### Security
|
||||||
|
- Static-FE: Fix remote posts not being sanitized
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- 500 errors when no `Accept` header is present if Static-FE is enabled
|
||||||
|
- Instance panel not being updated immediately due to wrong `Cache-Control` headers
|
||||||
|
- Statuses posted with BBCode/Markdown having unncessary newlines in Pleroma-FE
|
||||||
|
- OTP: Fix some settings not being migrated to in-database config properly
|
||||||
|
- No `Cache-Control` headers on attachment/media proxy requests
|
||||||
|
- Character limit enforcement being off by 1
|
||||||
|
- Mastodon Streaming API: hashtag timelines not working
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- BBCode and Markdown formatters will no longer return any `\n` and only use `<br/>` for newlines
|
||||||
|
- Mastodon API: Allow registration without email if email verification is not enabled
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
#### Nginx only
|
||||||
|
1. Remove `proxy_ignore_headers Cache-Control;` and `proxy_hide_header Cache-Control;` from your config.
|
||||||
|
|
||||||
|
#### Everyone
|
||||||
|
1. Run database migrations (inside Pleroma directory):
|
||||||
|
- OTP: `./bin/pleroma_ctl migrate`
|
||||||
|
- From Source: `mix ecto.migrate`
|
||||||
|
2. Restart Pleroma
|
||||||
|
|
||||||
## [2.0.0] - 2019-03-08
|
## [2.0.0] - 2019-03-08
|
||||||
### Security
|
### Security
|
||||||
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
|
- Mastodon API: Fix being able to request enormous amount of statuses in timelines leading to DoS. Now limited to 40 per request.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
|
- **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
|
||||||
|
|
|
@ -386,47 +386,56 @@ defp render_timelines(user) do
|
||||||
|
|
||||||
favourites = ActivityPub.fetch_favourites(user)
|
favourites = ActivityPub.fetch_favourites(user)
|
||||||
|
|
||||||
|
output_relationships =
|
||||||
|
!!Pleroma.Config.get([:extensions, :output_relationships_in_statuses_by_default])
|
||||||
|
|
||||||
Benchee.run(
|
Benchee.run(
|
||||||
%{
|
%{
|
||||||
"Rendering home timeline" => fn ->
|
"Rendering home timeline" => fn ->
|
||||||
StatusView.render("index.json", %{
|
StatusView.render("index.json", %{
|
||||||
activities: home_activities,
|
activities: home_activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
"Rendering direct timeline" => fn ->
|
"Rendering direct timeline" => fn ->
|
||||||
StatusView.render("index.json", %{
|
StatusView.render("index.json", %{
|
||||||
activities: direct_activities,
|
activities: direct_activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
"Rendering public timeline" => fn ->
|
"Rendering public timeline" => fn ->
|
||||||
StatusView.render("index.json", %{
|
StatusView.render("index.json", %{
|
||||||
activities: public_activities,
|
activities: public_activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
"Rendering tag timeline" => fn ->
|
"Rendering tag timeline" => fn ->
|
||||||
StatusView.render("index.json", %{
|
StatusView.render("index.json", %{
|
||||||
activities: tag_activities,
|
activities: tag_activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
"Rendering notifications" => fn ->
|
"Rendering notifications" => fn ->
|
||||||
Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
|
Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
|
||||||
notifications: notifications,
|
notifications: notifications,
|
||||||
for: user
|
for: user,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
"Rendering favourites timeline" => fn ->
|
"Rendering favourites timeline" => fn ->
|
||||||
StatusView.render("index.json", %{
|
StatusView.render("index.json", %{
|
||||||
activities: favourites,
|
activities: favourites,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: !output_relationships
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
|
|
|
@ -240,6 +240,8 @@
|
||||||
extended_nickname_format: true,
|
extended_nickname_format: true,
|
||||||
cleanup_attachments: false
|
cleanup_attachments: false
|
||||||
|
|
||||||
|
config :pleroma, :extensions, output_relationships_in_statuses_by_default: true
|
||||||
|
|
||||||
config :pleroma, :feed,
|
config :pleroma, :feed,
|
||||||
post_title: %{
|
post_title: %{
|
||||||
max_length: 100,
|
max_length: 100,
|
||||||
|
|
|
@ -113,7 +113,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def describe do
|
def describe do
|
||||||
{:ok, %{mrf_sample: %{content: "new message content"}}}`
|
{:ok, %{mrf_sample: %{content: "new message content"}}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
defmodule Mix.Pleroma do
|
defmodule Mix.Pleroma do
|
||||||
@doc "Common functions to be reused in mix tasks"
|
@doc "Common functions to be reused in mix tasks"
|
||||||
def start_pleroma do
|
def start_pleroma do
|
||||||
Mix.Task.run("app.start")
|
|
||||||
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
|
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
|
||||||
|
|
||||||
if Pleroma.Config.get(:env) != :test do
|
if Pleroma.Config.get(:env) != :test do
|
||||||
|
|
|
@ -67,7 +67,8 @@ def run(["render_timeline", nickname | _] = args) do
|
||||||
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
|
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
|
||||||
activities: activities,
|
activities: activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity
|
as: :activity,
|
||||||
|
skip_relationships: true
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,10 +54,19 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
|
||||||
[:pleroma, nil, :prometheus]
|
[:pleroma, nil, :prometheus]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
{logger, other} =
|
||||||
|
(Repo.all(ConfigDB) ++ deleted_settings)
|
||||||
|
|> Enum.map(&transform_and_merge/1)
|
||||||
|
|> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end)
|
||||||
|
|
||||||
|
logger
|
||||||
|
|> Enum.sort()
|
||||||
|
|> Enum.each(&configure/1)
|
||||||
|
|
||||||
started_applications = Application.started_applications()
|
started_applications = Application.started_applications()
|
||||||
|
|
||||||
(Repo.all(ConfigDB) ++ deleted_settings)
|
other
|
||||||
|> Enum.map(&merge_and_update/1)
|
|> Enum.map(&update/1)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|> Enum.reject(&(&1 in reject_restart))
|
|> Enum.reject(&(&1 in reject_restart))
|
||||||
|> maybe_set_pleroma_last()
|
|> maybe_set_pleroma_last()
|
||||||
|
@ -81,51 +90,66 @@ defp maybe_set_pleroma_last(apps) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp group_for_restart(:logger, key, _, merged_value) do
|
defp transform_and_merge(%{group: group, key: key, value: value} = setting) do
|
||||||
# change logger configuration in runtime, without restart
|
group = ConfigDB.from_string(group)
|
||||||
if Keyword.keyword?(merged_value) and
|
key = ConfigDB.from_string(key)
|
||||||
key not in [:compile_time_application, :backends, :compile_time_purge_matching] do
|
value = ConfigDB.from_binary(value)
|
||||||
Logger.configure_backend(key, merged_value)
|
|
||||||
else
|
|
||||||
Logger.configure([{key, merged_value}])
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
default = Config.Holder.default_config(group, key)
|
||||||
|
|
||||||
|
merged =
|
||||||
|
cond do
|
||||||
|
Ecto.get_meta(setting, :state) == :deleted -> default
|
||||||
|
can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
|
||||||
|
true -> value
|
||||||
|
end
|
||||||
|
|
||||||
|
{group, key, value, merged}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp group_for_restart(group, _, _, _) when group != :pleroma, do: group
|
# change logger configuration in runtime, without restart
|
||||||
|
defp configure({:quack, key, _, merged}) do
|
||||||
defp group_for_restart(group, key, value, _) do
|
Logger.configure_backend(Quack.Logger, [{key, merged}])
|
||||||
if pleroma_need_restart?(group, key, value), do: group
|
:ok = update_env(:quack, key, merged)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp merge_and_update(setting) do
|
defp configure({_, :backends, _, merged}) do
|
||||||
|
# removing current backends
|
||||||
|
Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
|
||||||
|
|
||||||
|
Enum.each(merged, &Logger.add_backend/1)
|
||||||
|
|
||||||
|
:ok = update_env(:logger, :backends, merged)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp configure({group, key, _, merged}) do
|
||||||
|
merged =
|
||||||
|
if key == :console do
|
||||||
|
put_in(merged[:format], merged[:format] <> "\n")
|
||||||
|
else
|
||||||
|
merged
|
||||||
|
end
|
||||||
|
|
||||||
|
backend =
|
||||||
|
if key == :ex_syslogger,
|
||||||
|
do: {ExSyslogger, :ex_syslogger},
|
||||||
|
else: key
|
||||||
|
|
||||||
|
Logger.configure_backend(backend, merged)
|
||||||
|
:ok = update_env(:logger, group, merged)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update({group, key, value, merged}) do
|
||||||
try do
|
try do
|
||||||
key = ConfigDB.from_string(setting.key)
|
:ok = update_env(group, key, merged)
|
||||||
group = ConfigDB.from_string(setting.group)
|
|
||||||
|
|
||||||
default = Config.Holder.default_config(group, key)
|
if group != :pleroma or pleroma_need_restart?(group, key, value), do: group
|
||||||
value = ConfigDB.from_binary(setting.value)
|
|
||||||
|
|
||||||
merged_value =
|
|
||||||
cond do
|
|
||||||
Ecto.get_meta(setting, :state) == :deleted -> default
|
|
||||||
can_be_merged?(default, value) -> ConfigDB.merge_group(group, key, default, value)
|
|
||||||
true -> value
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok = update_env(group, key, merged_value)
|
|
||||||
|
|
||||||
group_for_restart(group, key, value, merged_value)
|
|
||||||
rescue
|
rescue
|
||||||
error ->
|
error ->
|
||||||
error_msg =
|
error_msg =
|
||||||
"updating env causes error, group: " <>
|
"updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
|
||||||
inspect(setting.group) <>
|
inspect(value)
|
||||||
" key: " <>
|
} error: #{inspect(error)}"
|
||||||
inspect(setting.key) <>
|
|
||||||
" value: " <>
|
|
||||||
inspect(ConfigDB.from_binary(setting.value)) <> " error: " <> inspect(error)
|
|
||||||
|
|
||||||
Logger.warn(error_msg)
|
Logger.warn(error_msg)
|
||||||
|
|
||||||
|
@ -133,6 +157,9 @@ defp merge_and_update(setting) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp update_env(group, key, nil), do: Application.delete_env(group, key)
|
||||||
|
defp update_env(group, key, value), do: Application.put_env(group, key, value)
|
||||||
|
|
||||||
@spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
|
@spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
|
||||||
def pleroma_need_restart?(group, key, value) do
|
def pleroma_need_restart?(group, key, value) do
|
||||||
group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
|
group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
|
||||||
|
@ -150,9 +177,6 @@ defp group_and_subkey_need_reboot?(group, key, value) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp update_env(group, key, nil), do: Application.delete_env(group, key)
|
|
||||||
defp update_env(group, key, value), do: Application.put_env(group, key, value)
|
|
||||||
|
|
||||||
defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
|
defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
|
||||||
|
|
||||||
defp restart(started_applications, app, _) do
|
defp restart(started_applications, app, _) do
|
||||||
|
|
|
@ -4,10 +4,16 @@
|
||||||
|
|
||||||
import EctoEnum
|
import EctoEnum
|
||||||
|
|
||||||
defenum(UserRelationshipTypeEnum,
|
defenum(Pleroma.UserRelationship.Type,
|
||||||
block: 1,
|
block: 1,
|
||||||
mute: 2,
|
mute: 2,
|
||||||
reblog_mute: 3,
|
reblog_mute: 3,
|
||||||
notification_mute: 4,
|
notification_mute: 4,
|
||||||
inverse_subscription: 5
|
inverse_subscription: 5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
defenum(Pleroma.FollowingRelationship.State,
|
||||||
|
follow_pending: 1,
|
||||||
|
follow_accept: 2,
|
||||||
|
follow_reject: 3
|
||||||
|
)
|
||||||
|
|
|
@ -8,12 +8,13 @@ defmodule Pleroma.FollowingRelationship do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Ecto.Changeset
|
||||||
alias FlakeId.Ecto.CompatType
|
alias FlakeId.Ecto.CompatType
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
schema "following_relationships" do
|
schema "following_relationships" do
|
||||||
field(:state, :string, default: "accept")
|
field(:state, Pleroma.FollowingRelationship.State, default: :follow_pending)
|
||||||
|
|
||||||
belongs_to(:follower, User, type: CompatType)
|
belongs_to(:follower, User, type: CompatType)
|
||||||
belongs_to(:following, User, type: CompatType)
|
belongs_to(:following, User, type: CompatType)
|
||||||
|
@ -27,6 +28,18 @@ def changeset(%__MODULE__{} = following_relationship, attrs) do
|
||||||
|> put_assoc(:follower, attrs.follower)
|
|> put_assoc(:follower, attrs.follower)
|
||||||
|> put_assoc(:following, attrs.following)
|
|> put_assoc(:following, attrs.following)
|
||||||
|> validate_required([:state, :follower, :following])
|
|> validate_required([:state, :follower, :following])
|
||||||
|
|> unique_constraint(:follower_id,
|
||||||
|
name: :following_relationships_follower_id_following_id_index
|
||||||
|
)
|
||||||
|
|> validate_not_self_relationship()
|
||||||
|
end
|
||||||
|
|
||||||
|
def state_to_enum(state) when state in ["pending", "accept", "reject"] do
|
||||||
|
String.to_existing_atom("follow_#{state}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def state_to_enum(state) do
|
||||||
|
raise "State is not convertible to Pleroma.FollowingRelationship.State: #{state}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(%User{} = follower, %User{} = following) do
|
def get(%User{} = follower, %User{} = following) do
|
||||||
|
@ -35,7 +48,7 @@ def get(%User{} = follower, %User{} = following) do
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(follower, following, "reject"), do: unfollow(follower, following)
|
def update(follower, following, :follow_reject), do: unfollow(follower, following)
|
||||||
|
|
||||||
def update(%User{} = follower, %User{} = following, state) do
|
def update(%User{} = follower, %User{} = following, state) do
|
||||||
case get(follower, following) do
|
case get(follower, following) do
|
||||||
|
@ -50,7 +63,7 @@ def update(%User{} = follower, %User{} = following, state) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow(%User{} = follower, %User{} = following, state \\ "accept") do
|
def follow(%User{} = follower, %User{} = following, state \\ :follow_accept) do
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> changeset(%{follower: follower, following: following, state: state})
|
|> changeset(%{follower: follower, following: following, state: state})
|
||||||
|> Repo.insert(on_conflict: :nothing)
|
|> Repo.insert(on_conflict: :nothing)
|
||||||
|
@ -80,7 +93,7 @@ def following_count(%User{} = user) do
|
||||||
def get_follow_requests(%User{id: id}) do
|
def get_follow_requests(%User{id: id}) do
|
||||||
__MODULE__
|
__MODULE__
|
||||||
|> join(:inner, [r], f in assoc(r, :follower))
|
|> join(:inner, [r], f in assoc(r, :follower))
|
||||||
|> where([r], r.state == "pending")
|
|> where([r], r.state == ^:follow_pending)
|
||||||
|> where([r], r.following_id == ^id)
|
|> where([r], r.following_id == ^id)
|
||||||
|> select([r, f], f)
|
|> select([r, f], f)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
@ -88,7 +101,7 @@ def get_follow_requests(%User{id: id}) do
|
||||||
|
|
||||||
def following?(%User{id: follower_id}, %User{id: followed_id}) do
|
def following?(%User{id: follower_id}, %User{id: followed_id}) do
|
||||||
__MODULE__
|
__MODULE__
|
||||||
|> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept")
|
|> where(follower_id: ^follower_id, following_id: ^followed_id, state: ^:follow_accept)
|
||||||
|> Repo.exists?()
|
|> Repo.exists?()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -97,7 +110,7 @@ def following(%User{} = user) do
|
||||||
__MODULE__
|
__MODULE__
|
||||||
|> join(:inner, [r], u in User, on: r.following_id == u.id)
|
|> join(:inner, [r], u in User, on: r.following_id == u.id)
|
||||||
|> where([r], r.follower_id == ^user.id)
|
|> where([r], r.follower_id == ^user.id)
|
||||||
|> where([r], r.state == "accept")
|
|> where([r], r.state == ^:follow_accept)
|
||||||
|> select([r, u], u.follower_address)
|
|> select([r, u], u.follower_address)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
|
||||||
|
@ -157,4 +170,30 @@ def find(following_relationships, follower, following) do
|
||||||
fr -> fr.follower_id == follower.id and fr.following_id == following.id
|
fr -> fr.follower_id == follower.id and fr.following_id == following.id
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_not_self_relationship(%Changeset{} = changeset) do
|
||||||
|
changeset
|
||||||
|
|> validate_follower_id_following_id_inequality()
|
||||||
|
|> validate_following_id_follower_id_inequality()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp validate_follower_id_following_id_inequality(%Changeset{} = changeset) do
|
||||||
|
validate_change(changeset, :follower_id, fn _, follower_id ->
|
||||||
|
if follower_id == get_field(changeset, :following_id) do
|
||||||
|
[source_id: "can't be equal to following_id"]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp validate_following_id_follower_id_inequality(%Changeset{} = changeset) do
|
||||||
|
validate_change(changeset, :following_id, fn _, following_id ->
|
||||||
|
if following_id == get_field(changeset, :follower_id) do
|
||||||
|
[target_id: "can't be equal to follower_id"]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,13 +42,13 @@ def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = con
|
||||||
else
|
else
|
||||||
{:user_match, false} ->
|
{:user_match, false} ->
|
||||||
Logger.debug("Failed to map identity from signature (payload actor mismatch)")
|
Logger.debug("Failed to map identity from signature (payload actor mismatch)")
|
||||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{inspect(actor)}")
|
||||||
assign(conn, :valid_signature, false)
|
assign(conn, :valid_signature, false)
|
||||||
|
|
||||||
# remove me once testsuite uses mapped capabilities instead of what we do now
|
# remove me once testsuite uses mapped capabilities instead of what we do now
|
||||||
{:user, nil} ->
|
{:user, nil} ->
|
||||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}, actor=#{actor}")
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -60,7 +60,7 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
||||||
Logger.debug("key_id=#{key_id_from_conn(conn)}")
|
Logger.debug("key_id=#{inspect(key_id_from_conn(conn))}")
|
||||||
assign(conn, :valid_signature, false)
|
assign(conn, :valid_signature, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -110,20 +110,9 @@ defp handle(conn, action_settings) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def disabled?(conn) do
|
def disabled?(conn) do
|
||||||
localhost_or_socket =
|
if Map.has_key?(conn.assigns, :remote_ip_found),
|
||||||
case Config.get([Pleroma.Web.Endpoint, :http, :ip]) do
|
do: !conn.assigns.remote_ip_found,
|
||||||
{127, 0, 0, 1} -> true
|
else: false
|
||||||
{0, 0, 0, 0, 0, 0, 0, 1} -> true
|
|
||||||
{:local, _} -> true
|
|
||||||
_ -> false
|
|
||||||
end
|
|
||||||
|
|
||||||
remote_ip_not_found =
|
|
||||||
if Map.has_key?(conn.assigns, :remote_ip_found),
|
|
||||||
do: !conn.assigns.remote_ip_found,
|
|
||||||
else: false
|
|
||||||
|
|
||||||
localhost_or_socket and remote_ip_not_found
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@inspect_bucket_not_found {:error, :not_found}
|
@inspect_bucket_not_found {:error, :not_found}
|
||||||
|
|
|
@ -7,8 +7,6 @@ defmodule Pleroma.Plugs.RemoteIp do
|
||||||
This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
|
This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import Plug.Conn
|
|
||||||
|
|
||||||
@behaviour Plug
|
@behaviour Plug
|
||||||
|
|
||||||
@headers ~w[
|
@headers ~w[
|
||||||
|
@ -28,12 +26,11 @@ defmodule Pleroma.Plugs.RemoteIp do
|
||||||
|
|
||||||
def init(_), do: nil
|
def init(_), do: nil
|
||||||
|
|
||||||
def call(%{remote_ip: original_remote_ip} = conn, _) do
|
def call(conn, _) do
|
||||||
config = Pleroma.Config.get(__MODULE__, [])
|
config = Pleroma.Config.get(__MODULE__, [])
|
||||||
|
|
||||||
if Keyword.get(config, :enabled, false) do
|
if Keyword.get(config, :enabled, false) do
|
||||||
%{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts(config))
|
RemoteIp.call(conn, remote_ip_opts(config))
|
||||||
assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip)
|
|
||||||
else
|
else
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,6 +41,7 @@ def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
|
||||||
conn ->
|
conn ->
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
|
|> merge_resp_headers([{"content-security-policy", "sandbox"}])
|
||||||
|
|
||||||
config = Pleroma.Config.get(Pleroma.Upload)
|
config = Pleroma.Config.get(Pleroma.Upload)
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ def handle_info({:gun_down, conn_pid, _protocol, _reason, _killed}, state) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:DOWN, _ref, :process, conn_pid, reason}, state) do
|
def handle_info({:DOWN, _ref, :process, conn_pid, reason}, state) do
|
||||||
Logger.debug("received DOWM message for #{inspect(conn_pid)} reason -> #{inspect(reason)}")
|
Logger.debug("received DOWN message for #{inspect(conn_pid)} reason -> #{inspect(reason)}")
|
||||||
|
|
||||||
state =
|
state =
|
||||||
with {key, conn} <- find_conn(state.conns, conn_pid) do
|
with {key, conn} <- find_conn(state.conns, conn_pid) do
|
||||||
|
|
|
@ -351,18 +351,26 @@ defp fix_follower_address(%{nickname: nickname} = params),
|
||||||
|
|
||||||
defp fix_follower_address(params), do: params
|
defp fix_follower_address(params), do: params
|
||||||
|
|
||||||
def remote_user_creation(params) do
|
def remote_user_changeset(struct \\ %User{local: false}, params) do
|
||||||
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
||||||
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
||||||
|
|
||||||
|
name =
|
||||||
|
case params[:name] do
|
||||||
|
name when is_binary(name) and byte_size(name) > 0 -> name
|
||||||
|
_ -> params[:nickname]
|
||||||
|
end
|
||||||
|
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|
|> Map.put(:name, name)
|
||||||
|
|> Map.put_new(:last_refreshed_at, NaiveDateTime.utc_now())
|
||||||
|> truncate_if_exists(:name, name_limit)
|
|> truncate_if_exists(:name, name_limit)
|
||||||
|> truncate_if_exists(:bio, bio_limit)
|
|> truncate_if_exists(:bio, bio_limit)
|
||||||
|> truncate_fields_param()
|
|> truncate_fields_param()
|
||||||
|> fix_follower_address()
|
|> fix_follower_address()
|
||||||
|
|
||||||
%User{local: false}
|
struct
|
||||||
|> cast(
|
|> cast(
|
||||||
params,
|
params,
|
||||||
[
|
[
|
||||||
|
@ -378,6 +386,7 @@ def remote_user_creation(params) do
|
||||||
:ap_enabled,
|
:ap_enabled,
|
||||||
:banner,
|
:banner,
|
||||||
:locked,
|
:locked,
|
||||||
|
:last_refreshed_at,
|
||||||
:magic_key,
|
:magic_key,
|
||||||
:uri,
|
:uri,
|
||||||
:follower_address,
|
:follower_address,
|
||||||
|
@ -511,52 +520,6 @@ defp put_upload(value, type) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do
|
|
||||||
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
|
||||||
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
|
|
||||||
|
|
||||||
params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now())
|
|
||||||
|
|
||||||
params = if remote?, do: truncate_fields_param(params), else: params
|
|
||||||
|
|
||||||
struct
|
|
||||||
|> cast(
|
|
||||||
params,
|
|
||||||
[
|
|
||||||
:bio,
|
|
||||||
:name,
|
|
||||||
:emoji,
|
|
||||||
:follower_address,
|
|
||||||
:following_address,
|
|
||||||
:public_key,
|
|
||||||
:inbox,
|
|
||||||
:shared_inbox,
|
|
||||||
:avatar,
|
|
||||||
:last_refreshed_at,
|
|
||||||
:ap_enabled,
|
|
||||||
:banner,
|
|
||||||
:locked,
|
|
||||||
:magic_key,
|
|
||||||
:follower_count,
|
|
||||||
:following_count,
|
|
||||||
:hide_follows,
|
|
||||||
:fields,
|
|
||||||
:hide_followers,
|
|
||||||
:allow_following_move,
|
|
||||||
:discoverable,
|
|
||||||
:hide_followers_count,
|
|
||||||
:hide_follows_count,
|
|
||||||
:actor_type,
|
|
||||||
:also_known_as
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|> unique_constraint(:nickname)
|
|
||||||
|> validate_format(:nickname, local_nickname_regex())
|
|
||||||
|> validate_length(:bio, max: bio_limit)
|
|
||||||
|> validate_length(:name, max: name_limit)
|
|
||||||
|> validate_fields(remote?)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_as_admin_changeset(struct, params) do
|
def update_as_admin_changeset(struct, params) do
|
||||||
struct
|
struct
|
||||||
|> update_changeset(params)
|
|> update_changeset(params)
|
||||||
|
@ -726,7 +689,7 @@ def needs_update?(_), do: true
|
||||||
|
|
||||||
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
|
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
|
||||||
def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true} = followed) do
|
def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true} = followed) do
|
||||||
follow(follower, followed, "pending")
|
follow(follower, followed, :follow_pending)
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do
|
def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do
|
||||||
|
@ -746,14 +709,14 @@ def maybe_direct_follow(%User{} = follower, %User{} = followed) do
|
||||||
def follow_all(follower, followeds) do
|
def follow_all(follower, followeds) do
|
||||||
followeds
|
followeds
|
||||||
|> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end)
|
|> Enum.reject(fn followed -> blocks?(follower, followed) || blocks?(followed, follower) end)
|
||||||
|> Enum.each(&follow(follower, &1, "accept"))
|
|> Enum.each(&follow(follower, &1, :follow_accept))
|
||||||
|
|
||||||
set_cache(follower)
|
set_cache(follower)
|
||||||
end
|
end
|
||||||
|
|
||||||
defdelegate following(user), to: FollowingRelationship
|
defdelegate following(user), to: FollowingRelationship
|
||||||
|
|
||||||
def follow(%User{} = follower, %User{} = followed, state \\ "accept") do
|
def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
|
||||||
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
|
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
@ -780,7 +743,7 @@ def unfollow(%User{ap_id: ap_id}, %User{ap_id: ap_id}) do
|
||||||
|
|
||||||
def unfollow(%User{} = follower, %User{} = followed) do
|
def unfollow(%User{} = follower, %User{} = followed) do
|
||||||
case get_follow_state(follower, followed) do
|
case get_follow_state(follower, followed) do
|
||||||
state when state in ["accept", "pending"] ->
|
state when state in [:follow_pending, :follow_accept] ->
|
||||||
FollowingRelationship.unfollow(follower, followed)
|
FollowingRelationship.unfollow(follower, followed)
|
||||||
{:ok, followed} = update_follower_count(followed)
|
{:ok, followed} = update_follower_count(followed)
|
||||||
|
|
||||||
|
@ -798,6 +761,7 @@ def unfollow(%User{} = follower, %User{} = followed) do
|
||||||
|
|
||||||
defdelegate following?(follower, followed), to: FollowingRelationship
|
defdelegate following?(follower, followed), to: FollowingRelationship
|
||||||
|
|
||||||
|
@doc "Returns follow state as Pleroma.FollowingRelationship.State value"
|
||||||
def get_follow_state(%User{} = follower, %User{} = following) do
|
def get_follow_state(%User{} = follower, %User{} = following) do
|
||||||
following_relationship = FollowingRelationship.get(follower, following)
|
following_relationship = FollowingRelationship.get(follower, following)
|
||||||
get_follow_state(follower, following, following_relationship)
|
get_follow_state(follower, following, following_relationship)
|
||||||
|
@ -811,8 +775,11 @@ def get_follow_state(
|
||||||
case {following_relationship, following.local} do
|
case {following_relationship, following.local} do
|
||||||
{nil, false} ->
|
{nil, false} ->
|
||||||
case Utils.fetch_latest_follow(follower, following) do
|
case Utils.fetch_latest_follow(follower, following) do
|
||||||
%{data: %{"state" => state}} when state in ["pending", "accept"] -> state
|
%Activity{data: %{"state" => state}} when state in ["pending", "accept"] ->
|
||||||
_ -> nil
|
FollowingRelationship.state_to_enum(state)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
{%{state: state}, _} ->
|
{%{state: state}, _} ->
|
||||||
|
@ -1311,7 +1278,7 @@ def blocks?(nil, _), do: false
|
||||||
|
|
||||||
def blocks?(%User{} = user, %User{} = target) do
|
def blocks?(%User{} = user, %User{} = target) do
|
||||||
blocks_user?(user, target) ||
|
blocks_user?(user, target) ||
|
||||||
(!User.following?(user, target) && blocks_domain?(user, target))
|
(blocks_domain?(user, target) and not User.following?(user, target))
|
||||||
end
|
end
|
||||||
|
|
||||||
def blocks_user?(%User{} = user, %User{} = target) do
|
def blocks_user?(%User{} = user, %User{} = target) do
|
||||||
|
@ -1664,17 +1631,6 @@ def get_public_key_for_ap_id(ap_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp blank?(""), do: nil
|
|
||||||
defp blank?(n), do: n
|
|
||||||
|
|
||||||
def insert_or_update_user(data) do
|
|
||||||
data
|
|
||||||
|> Map.put(:name, blank?(data[:name]) || data[:nickname])
|
|
||||||
|> remote_user_creation()
|
|
||||||
|> Repo.insert(on_conflict: {:replace_all_except, [:id]}, conflict_target: :nickname)
|
|
||||||
|> set_cache()
|
|
||||||
end
|
|
||||||
|
|
||||||
def ap_enabled?(%User{local: true}), do: true
|
def ap_enabled?(%User{local: true}), do: true
|
||||||
def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
|
def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
|
||||||
def ap_enabled?(_), do: false
|
def ap_enabled?(_), do: false
|
||||||
|
|
|
@ -148,7 +148,7 @@ defp compose_query({:followers, %User{id: id}}, query) do
|
||||||
as: :relationships,
|
as: :relationships,
|
||||||
on: r.following_id == ^id and r.follower_id == u.id
|
on: r.following_id == ^id and r.follower_id == u.id
|
||||||
)
|
)
|
||||||
|> where([relationships: r], r.state == "accept")
|
|> where([relationships: r], r.state == ^:follow_accept)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp compose_query({:friends, %User{id: id}}, query) do
|
defp compose_query({:friends, %User{id: id}}, query) do
|
||||||
|
@ -158,7 +158,7 @@ defp compose_query({:friends, %User{id: id}}, query) do
|
||||||
as: :relationships,
|
as: :relationships,
|
||||||
on: r.following_id == u.id and r.follower_id == ^id
|
on: r.following_id == u.id and r.follower_id == ^id
|
||||||
)
|
)
|
||||||
|> where([relationships: r], r.state == "accept")
|
|> where([relationships: r], r.state == ^:follow_accept)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp compose_query({:recipients_from_activity, to}, query) do
|
defp compose_query({:recipients_from_activity, to}, query) do
|
||||||
|
@ -173,7 +173,7 @@ defp compose_query({:recipients_from_activity, to}, query) do
|
||||||
)
|
)
|
||||||
|> where(
|
|> where(
|
||||||
[u, following: f, relationships: r],
|
[u, following: f, relationships: r],
|
||||||
u.ap_id in ^to or (f.follower_address in ^to and r.state == "accept")
|
u.ap_id in ^to or (f.follower_address in ^to and r.state == ^:follow_accept)
|
||||||
)
|
)
|
||||||
|> distinct(true)
|
|> distinct(true)
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.UserRelationship do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Ecto.Changeset
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
@ -16,12 +17,12 @@ defmodule Pleroma.UserRelationship do
|
||||||
schema "user_relationships" do
|
schema "user_relationships" do
|
||||||
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
|
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
|
||||||
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
|
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
|
||||||
field(:relationship_type, UserRelationshipTypeEnum)
|
field(:relationship_type, Pleroma.UserRelationship.Type)
|
||||||
|
|
||||||
timestamps(updated_at: false)
|
timestamps(updated_at: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
for relationship_type <- Keyword.keys(UserRelationshipTypeEnum.__enum_map__()) do
|
for relationship_type <- Keyword.keys(Pleroma.UserRelationship.Type.__enum_map__()) do
|
||||||
# `def create_block/2`, `def create_mute/2`, `def create_reblog_mute/2`,
|
# `def create_block/2`, `def create_mute/2`, `def create_reblog_mute/2`,
|
||||||
# `def create_notification_mute/2`, `def create_inverse_subscription/2`
|
# `def create_notification_mute/2`, `def create_inverse_subscription/2`
|
||||||
def unquote(:"create_#{relationship_type}")(source, target),
|
def unquote(:"create_#{relationship_type}")(source, target),
|
||||||
|
@ -40,7 +41,7 @@ def unquote(:"#{relationship_type}_exists?")(source, target),
|
||||||
|
|
||||||
def user_relationship_types, do: Keyword.keys(user_relationship_mappings())
|
def user_relationship_types, do: Keyword.keys(user_relationship_mappings())
|
||||||
|
|
||||||
def user_relationship_mappings, do: UserRelationshipTypeEnum.__enum_map__()
|
def user_relationship_mappings, do: Pleroma.UserRelationship.Type.__enum_map__()
|
||||||
|
|
||||||
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
|
def changeset(%UserRelationship{} = user_relationship, params \\ %{}) do
|
||||||
user_relationship
|
user_relationship
|
||||||
|
@ -129,17 +130,27 @@ def exists?(dictionary, rel_type, source, target, func) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc ":relationships option for StatusView / AccountView / NotificationView"
|
@doc ":relationships option for StatusView / AccountView / NotificationView"
|
||||||
def view_relationships_option(nil = _reading_user, _actors) do
|
def view_relationships_option(reading_user, actors, opts \\ [])
|
||||||
|
|
||||||
|
def view_relationships_option(nil = _reading_user, _actors, _opts) do
|
||||||
%{user_relationships: [], following_relationships: []}
|
%{user_relationships: [], following_relationships: []}
|
||||||
end
|
end
|
||||||
|
|
||||||
def view_relationships_option(%User{} = reading_user, actors) do
|
def view_relationships_option(%User{} = reading_user, actors, opts) do
|
||||||
|
{source_to_target_rel_types, target_to_source_rel_types} =
|
||||||
|
if opts[:source_mutes_only] do
|
||||||
|
# This option is used for rendering statuses (FE needs `muted` flag for each one anyways)
|
||||||
|
{[:mute], []}
|
||||||
|
else
|
||||||
|
{[:block, :mute, :notification_mute, :reblog_mute], [:block, :inverse_subscription]}
|
||||||
|
end
|
||||||
|
|
||||||
user_relationships =
|
user_relationships =
|
||||||
UserRelationship.dictionary(
|
UserRelationship.dictionary(
|
||||||
[reading_user],
|
[reading_user],
|
||||||
actors,
|
actors,
|
||||||
[:block, :mute, :notification_mute, :reblog_mute],
|
source_to_target_rel_types,
|
||||||
[:block, :inverse_subscription]
|
target_to_source_rel_types
|
||||||
)
|
)
|
||||||
|
|
||||||
following_relationships = FollowingRelationship.all_between_user_sets([reading_user], actors)
|
following_relationships = FollowingRelationship.all_between_user_sets([reading_user], actors)
|
||||||
|
@ -147,16 +158,14 @@ def view_relationships_option(%User{} = reading_user, actors) do
|
||||||
%{user_relationships: user_relationships, following_relationships: following_relationships}
|
%{user_relationships: user_relationships, following_relationships: following_relationships}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
|
defp validate_not_self_relationship(%Changeset{} = changeset) do
|
||||||
changeset
|
changeset
|
||||||
|> validate_change(:target_id, fn _, target_id ->
|
|> validate_source_id_target_id_inequality()
|
||||||
if target_id == get_field(changeset, :source_id) do
|
|> validate_target_id_source_id_inequality()
|
||||||
[target_id: "can't be equal to source_id"]
|
end
|
||||||
else
|
|
||||||
[]
|
defp validate_source_id_target_id_inequality(%Changeset{} = changeset) do
|
||||||
end
|
validate_change(changeset, :source_id, fn _, source_id ->
|
||||||
end)
|
|
||||||
|> validate_change(:source_id, fn _, source_id ->
|
|
||||||
if source_id == get_field(changeset, :target_id) do
|
if source_id == get_field(changeset, :target_id) do
|
||||||
[source_id: "can't be equal to target_id"]
|
[source_id: "can't be equal to target_id"]
|
||||||
else
|
else
|
||||||
|
@ -164,4 +173,14 @@ defp validate_not_self_relationship(%Ecto.Changeset{} = changeset) do
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_target_id_source_id_inequality(%Changeset{} = changeset) do
|
||||||
|
validate_change(changeset, :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)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -721,7 +721,7 @@ def move(%User{} = origin, %User{} = target, local \\ true) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp fetch_activities_for_context_query(context, opts) do
|
def fetch_activities_for_context_query(context, opts) do
|
||||||
public = [Constants.as_public()]
|
public = [Constants.as_public()]
|
||||||
|
|
||||||
recipients =
|
recipients =
|
||||||
|
@ -1576,11 +1576,22 @@ def fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_user_from_ap_id(ap_id) do
|
def make_user_from_ap_id(ap_id) do
|
||||||
if _user = User.get_cached_by_ap_id(ap_id) do
|
user = User.get_cached_by_ap_id(ap_id)
|
||||||
|
|
||||||
|
if user && !User.ap_enabled?(user) do
|
||||||
Transmogrifier.upgrade_user_from_ap_id(ap_id)
|
Transmogrifier.upgrade_user_from_ap_id(ap_id)
|
||||||
else
|
else
|
||||||
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
|
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||||
User.insert_or_update_user(data)
|
if user do
|
||||||
|
user
|
||||||
|
|> User.remote_user_changeset(data)
|
||||||
|
|> User.update_and_set_cache()
|
||||||
|
else
|
||||||
|
data
|
||||||
|
|> User.remote_user_changeset()
|
||||||
|
|> Repo.insert()
|
||||||
|
|> User.set_cache()
|
||||||
|
end
|
||||||
else
|
else
|
||||||
e -> {:error, e}
|
e -> {:error, e}
|
||||||
end
|
end
|
||||||
|
|
|
@ -205,16 +205,46 @@ def fix_context(object) do
|
||||||
|> Map.put("conversation", context)
|
|> Map.put("conversation", context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp add_if_present(map, _key, nil), do: map
|
||||||
|
|
||||||
|
defp add_if_present(map, key, value) do
|
||||||
|
Map.put(map, key, value)
|
||||||
|
end
|
||||||
|
|
||||||
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
|
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
|
||||||
attachments =
|
attachments =
|
||||||
Enum.map(attachment, fn data ->
|
Enum.map(attachment, fn data ->
|
||||||
media_type = data["mediaType"] || data["mimeType"]
|
url =
|
||||||
href = data["url"] || data["href"]
|
cond do
|
||||||
url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}]
|
is_list(data["url"]) -> List.first(data["url"])
|
||||||
|
is_map(data["url"]) -> data["url"]
|
||||||
|
true -> nil
|
||||||
|
end
|
||||||
|
|
||||||
data
|
media_type =
|
||||||
|> Map.put("mediaType", media_type)
|
cond do
|
||||||
|> Map.put("url", url)
|
is_map(url) && is_binary(url["mediaType"]) -> url["mediaType"]
|
||||||
|
is_binary(data["mediaType"]) -> data["mediaType"]
|
||||||
|
is_binary(data["mimeType"]) -> data["mimeType"]
|
||||||
|
true -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
href =
|
||||||
|
cond do
|
||||||
|
is_map(url) && is_binary(url["href"]) -> url["href"]
|
||||||
|
is_binary(data["url"]) -> data["url"]
|
||||||
|
is_binary(data["href"]) -> data["href"]
|
||||||
|
end
|
||||||
|
|
||||||
|
attachment_url =
|
||||||
|
%{"href" => href}
|
||||||
|
|> add_if_present("mediaType", media_type)
|
||||||
|
|> add_if_present("type", Map.get(url || %{}, "type"))
|
||||||
|
|
||||||
|
%{"url" => [attachment_url]}
|
||||||
|
|> add_if_present("mediaType", media_type)
|
||||||
|
|> add_if_present("type", data["type"])
|
||||||
|
|> add_if_present("name", data["name"])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Map.put(object, "attachment", attachments)
|
Map.put(object, "attachment", attachments)
|
||||||
|
@ -494,7 +524,8 @@ def handle_incoming(
|
||||||
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
|
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
|
||||||
{_, {:ok, _}} <-
|
{_, {:ok, _}} <-
|
||||||
{:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
|
{:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
|
{:ok, _relationship} <-
|
||||||
|
FollowingRelationship.update(follower, followed, :follow_accept) do
|
||||||
ActivityPub.accept(%{
|
ActivityPub.accept(%{
|
||||||
to: [follower.ap_id],
|
to: [follower.ap_id],
|
||||||
actor: followed,
|
actor: followed,
|
||||||
|
@ -504,7 +535,7 @@ def handle_incoming(
|
||||||
else
|
else
|
||||||
{:user_blocked, true} ->
|
{:user_blocked, true} ->
|
||||||
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
|
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
|
||||||
{:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
|
{:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
|
||||||
|
|
||||||
ActivityPub.reject(%{
|
ActivityPub.reject(%{
|
||||||
to: [follower.ap_id],
|
to: [follower.ap_id],
|
||||||
|
@ -515,7 +546,7 @@ def handle_incoming(
|
||||||
|
|
||||||
{:follow, {:error, _}} ->
|
{:follow, {:error, _}} ->
|
||||||
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
|
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
|
||||||
{:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
|
{:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
|
||||||
|
|
||||||
ActivityPub.reject(%{
|
ActivityPub.reject(%{
|
||||||
to: [follower.ap_id],
|
to: [follower.ap_id],
|
||||||
|
@ -525,7 +556,7 @@ def handle_incoming(
|
||||||
})
|
})
|
||||||
|
|
||||||
{:user_locked, true} ->
|
{:user_locked, true} ->
|
||||||
{:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
|
{:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_pending)
|
||||||
:noop
|
:noop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -545,7 +576,7 @@ def handle_incoming(
|
||||||
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
||||||
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
|
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
|
||||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
|
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
|
||||||
ActivityPub.accept(%{
|
ActivityPub.accept(%{
|
||||||
to: follow_activity.data["to"],
|
to: follow_activity.data["to"],
|
||||||
type: "Accept",
|
type: "Accept",
|
||||||
|
@ -568,7 +599,7 @@ def handle_incoming(
|
||||||
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
||||||
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
|
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
|
||||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
|
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
|
||||||
{:ok, activity} <-
|
{:ok, activity} <-
|
||||||
ActivityPub.reject(%{
|
ActivityPub.reject(%{
|
||||||
to: follow_activity.data["to"],
|
to: follow_activity.data["to"],
|
||||||
|
@ -680,7 +711,7 @@ def handle_incoming(
|
||||||
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
||||||
|
|
||||||
actor
|
actor
|
||||||
|> User.upgrade_changeset(new_user_data, true)
|
|> User.remote_user_changeset(new_user_data)
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
ActivityPub.update(%{
|
ActivityPub.update(%{
|
||||||
|
@ -1223,12 +1254,8 @@ def perform(:user_upgrade, user) do
|
||||||
def upgrade_user_from_ap_id(ap_id) do
|
def upgrade_user_from_ap_id(ap_id) do
|
||||||
with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
|
with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
|
||||||
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
|
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
|
||||||
already_ap <- User.ap_enabled?(user),
|
{:ok, user} <- update_user(user, data) do
|
||||||
{:ok, user} <- upgrade_user(user, data) do
|
TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
|
||||||
if not already_ap do
|
|
||||||
TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
|
|
||||||
end
|
|
||||||
|
|
||||||
{:ok, user}
|
{:ok, user}
|
||||||
else
|
else
|
||||||
%User{} = user -> {:ok, user}
|
%User{} = user -> {:ok, user}
|
||||||
|
@ -1236,9 +1263,9 @@ def upgrade_user_from_ap_id(ap_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp upgrade_user(user, data) do
|
defp update_user(user, data) do
|
||||||
user
|
user
|
||||||
|> User.upgrade_changeset(data, true)
|
|> User.remote_user_changeset(data)
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ def list_instance_statuses(conn, %{"instance" => instance} = params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
||||||
|> render("index.json", %{activities: activities, as: :activity})
|
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
|
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
|
||||||
|
@ -277,7 +277,7 @@ def list_user_statuses(conn, %{"nickname" => nickname} = params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(StatusView)
|
|> put_view(StatusView)
|
||||||
|> render("index.json", %{activities: activities, as: :activity})
|
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|
||||||
else
|
else
|
||||||
_ -> {:error, :not_found}
|
_ -> {:error, :not_found}
|
||||||
end
|
end
|
||||||
|
@ -812,7 +812,7 @@ def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
||||||
|> render("index.json", %{activities: activities, as: :activity})
|
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|
||||||
end
|
end
|
||||||
|
|
||||||
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
|
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
|
||||||
|
|
|
@ -38,7 +38,12 @@ def render("show.json", %{report: report, user: user, account: account, statuses
|
||||||
actor: merge_account_views(user),
|
actor: merge_account_views(user),
|
||||||
content: content,
|
content: content,
|
||||||
created_at: created_at,
|
created_at: created_at,
|
||||||
statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
|
statuses:
|
||||||
|
StatusView.render("index.json", %{
|
||||||
|
activities: statuses,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: false
|
||||||
|
}),
|
||||||
state: report.data["state"],
|
state: report.data["state"],
|
||||||
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
|
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ def spec do
|
||||||
password: %OpenApiSpex.OAuthFlow{
|
password: %OpenApiSpex.OAuthFlow{
|
||||||
authorizationUrl: "/oauth/authorize",
|
authorizationUrl: "/oauth/authorize",
|
||||||
tokenUrl: "/oauth/token",
|
tokenUrl: "/oauth/token",
|
||||||
scopes: %{"read" => "read"}
|
scopes: %{"read" => "read", "write" => "write", "follow" => "follow"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Helpers do
|
defmodule Pleroma.Web.ApiSpec.Helpers do
|
||||||
def request_body(description, schema_ref, opts \\ []) do
|
def request_body(description, schema_ref, opts \\ []) do
|
||||||
media_types = ["application/json", "multipart/form-data"]
|
media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
|
||||||
|
|
||||||
content =
|
content =
|
||||||
media_types
|
media_types
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.DomainBlockOperation do
|
||||||
|
alias OpenApiSpex.Operation
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
alias Pleroma.Web.ApiSpec.Helpers
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
|
||||||
|
|
||||||
|
def open_api_operation(action) do
|
||||||
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
|
apply(__MODULE__, operation, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def index_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["domain_blocks"],
|
||||||
|
summary: "Fetch domain blocks",
|
||||||
|
description: "View domains the user has blocked.",
|
||||||
|
security: [%{"oAuth" => ["follow", "read:blocks"]}],
|
||||||
|
operationId: "DomainBlockController.index",
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Domain blocks", "application/json", DomainBlocksResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["domain_blocks"],
|
||||||
|
summary: "Block a domain",
|
||||||
|
description: """
|
||||||
|
Block a domain to:
|
||||||
|
|
||||||
|
- hide all public posts from it
|
||||||
|
- hide all notifications from it
|
||||||
|
- remove all followers from it
|
||||||
|
- prevent following new users from it (but does not remove existing follows)
|
||||||
|
""",
|
||||||
|
operationId: "DomainBlockController.create",
|
||||||
|
requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
|
||||||
|
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["domain_blocks"],
|
||||||
|
summary: "Unblock a domain",
|
||||||
|
description: "Remove a domain block, if it exists in the user's array of blocked domains.",
|
||||||
|
operationId: "DomainBlockController.delete",
|
||||||
|
requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
|
||||||
|
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
20
lib/pleroma/web/api_spec/schemas/domain_block_request.ex
Normal file
20
lib/pleroma/web/api_spec/schemas/domain_block_request.ex
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest do
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "DomainBlockRequest",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
domain: %Schema{type: :string}
|
||||||
|
},
|
||||||
|
required: [:domain],
|
||||||
|
example: %{
|
||||||
|
"domain" => "facebook.com"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
16
lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
Normal file
16
lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse do
|
||||||
|
require OpenApiSpex
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "DomainBlocksResponse",
|
||||||
|
description: "Response schema for domain blocks",
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{type: :string},
|
||||||
|
example: ["google.com", "facebook.com"]
|
||||||
|
})
|
||||||
|
end
|
|
@ -187,7 +187,7 @@ defp object(draft) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp preview?(draft) do
|
defp preview?(draft) do
|
||||||
preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"]) || false
|
preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"])
|
||||||
%__MODULE__{draft | preview?: preview?}
|
%__MODULE__{draft | preview?: preview?}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ def accept_follow_request(follower, followed) do
|
||||||
with {:ok, follower} <- User.follow(follower, followed),
|
with {:ok, follower} <- User.follow(follower, followed),
|
||||||
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
||||||
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
|
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept"),
|
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept),
|
||||||
{:ok, _activity} <-
|
{:ok, _activity} <-
|
||||||
ActivityPub.accept(%{
|
ActivityPub.accept(%{
|
||||||
to: [follower.ap_id],
|
to: [follower.ap_id],
|
||||||
|
@ -60,7 +60,7 @@ def accept_follow_request(follower, followed) do
|
||||||
def reject_follow_request(follower, followed) do
|
def reject_follow_request(follower, followed) do
|
||||||
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
|
||||||
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
|
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
|
||||||
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
|
{:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
|
||||||
{:ok, _activity} <-
|
{:ok, _activity} <-
|
||||||
ActivityPub.reject(%{
|
ActivityPub.reject(%{
|
||||||
to: [follower.ap_id],
|
to: [follower.ap_id],
|
||||||
|
|
|
@ -5,10 +5,18 @@
|
||||||
defmodule Pleroma.Web.ControllerHelper do
|
defmodule Pleroma.Web.ControllerHelper do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
# As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
alias Pleroma.Config
|
||||||
|
|
||||||
|
# As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
||||||
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
|
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
|
||||||
def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
|
|
||||||
def truthy_param?(value), do: value not in @falsy_param_values
|
def explicitly_falsy_param?(value), do: value in @falsy_param_values
|
||||||
|
|
||||||
|
# Note: `nil` and `""` are considered falsy values in Pleroma
|
||||||
|
def falsy_param?(value),
|
||||||
|
do: explicitly_falsy_param?(value) or value in [nil, ""]
|
||||||
|
|
||||||
|
def truthy_param?(value), do: not falsy_param?(value)
|
||||||
|
|
||||||
def json_response(conn, status, json) do
|
def json_response(conn, status, json) do
|
||||||
conn
|
conn
|
||||||
|
@ -96,4 +104,14 @@ def try_render(conn, _, _) do
|
||||||
def put_if_exist(map, _key, nil), do: map
|
def put_if_exist(map, _key, nil), do: map
|
||||||
|
|
||||||
def put_if_exist(map, key, value), do: Map.put(map, key, value)
|
def put_if_exist(map, key, value), do: Map.put(map, key, value)
|
||||||
|
|
||||||
|
@doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
|
||||||
|
def skip_relationships?(params) do
|
||||||
|
if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
|
||||||
|
false
|
||||||
|
else
|
||||||
|
# BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
|
||||||
|
not truthy_param?(params["with_relationships"])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper,
|
import Pleroma.Web.ControllerHelper,
|
||||||
only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
|
only: [
|
||||||
|
add_link_headers: 2,
|
||||||
|
truthy_param?: 1,
|
||||||
|
assign_account_by_id: 2,
|
||||||
|
json_response: 3,
|
||||||
|
skip_relationships?: 1
|
||||||
|
]
|
||||||
|
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Plugs.RateLimiter
|
alias Pleroma.Plugs.RateLimiter
|
||||||
|
@ -233,7 +239,12 @@ def statuses(%{assigns: %{user: reading_user}} = conn, params) do
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> put_view(StatusView)
|
|> put_view(StatusView)
|
||||||
|> render("index.json", activities: activities, for: reading_user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: reading_user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
_e -> render_error(conn, :not_found, "Can't find user")
|
_e -> render_error(conn, :not_found, "Can't find user")
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,9 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
plug(OpenApiSpex.Plug.CastAndValidate)
|
||||||
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DomainBlockOperation
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["follow", "read:blocks"]} when action == :index
|
%{scopes: ["follow", "read:blocks"]} when action == :index
|
||||||
|
@ -26,13 +29,13 @@ def index(%{assigns: %{user: user}} = conn, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "POST /api/v1/domain_blocks"
|
@doc "POST /api/v1/domain_blocks"
|
||||||
def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
|
def create(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
|
||||||
User.block_domain(blocker, domain)
|
User.block_domain(blocker, domain)
|
||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "DELETE /api/v1/domain_blocks"
|
@doc "DELETE /api/v1/domain_blocks"
|
||||||
def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
|
def delete(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
|
||||||
User.unblock_domain(blocker, domain)
|
User.unblock_domain(blocker, domain)
|
||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
|
||||||
|
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
@ -45,7 +45,11 @@ def index(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(notifications)
|
|> add_link_headers(notifications)
|
||||||
|> render("index.json", notifications: notifications, for: user)
|
|> render("index.json",
|
||||||
|
notifications: notifications,
|
||||||
|
for: user,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/notifications/:id
|
# GET /api/v1/notifications/:id
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.SearchController do
|
defmodule Pleroma.Web.MastodonAPI.SearchController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
import Pleroma.Web.ControllerHelper, only: [fetch_integer_param: 2, skip_relationships?: 1]
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Plugs.RateLimiter
|
alias Pleroma.Plugs.RateLimiter
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
alias Pleroma.Web.ControllerHelper
|
|
||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
|
||||||
|
@ -66,10 +67,11 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = para
|
||||||
|
|
||||||
defp search_options(params, user) do
|
defp search_options(params, user) do
|
||||||
[
|
[
|
||||||
|
skip_relationships: skip_relationships?(params),
|
||||||
resolve: params["resolve"] == "true",
|
resolve: params["resolve"] == "true",
|
||||||
following: params["following"] == "true",
|
following: params["following"] == "true",
|
||||||
limit: ControllerHelper.fetch_integer_param(params, "limit"),
|
limit: fetch_integer_param(params, "limit"),
|
||||||
offset: ControllerHelper.fetch_integer_param(params, "offset"),
|
offset: fetch_integer_param(params, "offset"),
|
||||||
type: params["type"],
|
type: params["type"],
|
||||||
author: get_author(params),
|
author: get_author(params),
|
||||||
for_user: user
|
for_user: user
|
||||||
|
@ -79,12 +81,24 @@ defp search_options(params, user) do
|
||||||
|
|
||||||
defp resource_search(_, "accounts", query, options) do
|
defp resource_search(_, "accounts", query, options) do
|
||||||
accounts = with_fallback(fn -> User.search(query, options) end)
|
accounts = with_fallback(fn -> User.search(query, options) end)
|
||||||
AccountView.render("index.json", users: accounts, for: options[:for_user], as: :user)
|
|
||||||
|
AccountView.render("index.json",
|
||||||
|
users: accounts,
|
||||||
|
for: options[:for_user],
|
||||||
|
as: :user,
|
||||||
|
skip_relationships: false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp resource_search(_, "statuses", query, options) do
|
defp resource_search(_, "statuses", query, options) do
|
||||||
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
|
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
|
||||||
StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
|
|
||||||
|
StatusView.render("index.json",
|
||||||
|
activities: statuses,
|
||||||
|
for: options[:for_user],
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: options[:skip_relationships]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp resource_search(:v2, "hashtags", query, _options) do
|
defp resource_search(:v2, "hashtags", query, _options) do
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.StatusController do
|
defmodule Pleroma.Web.MastodonAPI.StatusController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [try_render: 3, add_link_headers: 2]
|
import Pleroma.Web.ControllerHelper,
|
||||||
|
only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
|
||||||
|
|
||||||
require Ecto.Query
|
require Ecto.Query
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
||||||
|
|
||||||
`ids` query param is required
|
`ids` query param is required
|
||||||
"""
|
"""
|
||||||
def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
|
def index(%{assigns: %{user: user}} = conn, %{"ids" => ids} = params) do
|
||||||
limit = 100
|
limit = 100
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
|
@ -110,7 +111,12 @@ def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
|
||||||
|> Activity.all_by_ids_with_object()
|
|> Activity.all_by_ids_with_object()
|
||||||
|> Enum.filter(&Visibility.visible_for_user?(&1, user))
|
|> Enum.filter(&Visibility.visible_for_user?(&1, user))
|
||||||
|
|
||||||
render(conn, "index.json", activities: activities, for: user, as: :activity)
|
render(conn, "index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -360,7 +366,12 @@ def favourites(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/bookmarks"
|
@doc "GET /api/v1/bookmarks"
|
||||||
|
@ -378,6 +389,11 @@ def bookmarks(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(bookmarks)
|
|> add_link_headers(bookmarks)
|
||||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper,
|
import Pleroma.Web.ControllerHelper,
|
||||||
only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
|
only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1, skip_relationships?: 1]
|
||||||
|
|
||||||
alias Pleroma.Pagination
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
@ -14,9 +14,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
|
||||||
# TODO: Replace with a macro when there is a Phoenix release with
|
# TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
|
||||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||||
# in it
|
|
||||||
|
|
||||||
plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
|
plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
|
||||||
plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
|
plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
|
||||||
|
@ -49,7 +48,12 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/direct
|
# GET /api/v1/timelines/direct
|
||||||
|
@ -68,7 +72,12 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/public
|
# GET /api/v1/timelines/public
|
||||||
|
@ -95,7 +104,12 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities, %{"local" => local_only})
|
|> add_link_headers(activities, %{"local" => local_only})
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
render_error(conn, :unauthorized, "authorization required for timeline view")
|
render_error(conn, :unauthorized, "authorization required for timeline view")
|
||||||
end
|
end
|
||||||
|
@ -140,7 +154,12 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities, %{"local" => local_only})
|
|> add_link_headers(activities, %{"local" => local_only})
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/list/:list_id
|
# GET /api/v1/timelines/list/:list_id
|
||||||
|
@ -164,7 +183,12 @@ def list(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
|
||||||
|> ActivityPub.fetch_activities_bounded(following, params)
|
|> ActivityPub.fetch_activities_bounded(following, params)
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
||||||
render(conn, "index.json", activities: activities, for: user, as: :activity)
|
render(conn, "index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
_e -> render_error(conn, :forbidden, "Error.")
|
_e -> render_error(conn, :forbidden, "Error.")
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
||||||
def render("index.json", %{users: users} = opts) do
|
def render("index.json", %{users: users} = opts) do
|
||||||
reading_user = opts[:for]
|
reading_user = opts[:for]
|
||||||
|
|
||||||
|
# Note: :skip_relationships option is currently intentionally not supported for accounts
|
||||||
relationships_opt =
|
relationships_opt =
|
||||||
cond do
|
cond do
|
||||||
Map.has_key?(opts, :relationships) ->
|
Map.has_key?(opts, :relationships) ->
|
||||||
|
@ -73,7 +74,7 @@ def render(
|
||||||
followed_by =
|
followed_by =
|
||||||
if following_relationships do
|
if following_relationships do
|
||||||
case FollowingRelationship.find(following_relationships, target, reading_user) do
|
case FollowingRelationship.find(following_relationships, target, reading_user) do
|
||||||
%{state: "accept"} -> true
|
%{state: :follow_accept} -> true
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -83,7 +84,7 @@ def render(
|
||||||
# NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
|
# NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
|
||||||
%{
|
%{
|
||||||
id: to_string(target.id),
|
id: to_string(target.id),
|
||||||
following: follow_state == "accept",
|
following: follow_state == :follow_accept,
|
||||||
followed_by: followed_by,
|
followed_by: followed_by,
|
||||||
blocking:
|
blocking:
|
||||||
UserRelationship.exists?(
|
UserRelationship.exists?(
|
||||||
|
@ -125,7 +126,7 @@ def render(
|
||||||
reading_user,
|
reading_user,
|
||||||
&User.subscribed_to?(&2, &1)
|
&User.subscribed_to?(&2, &1)
|
||||||
),
|
),
|
||||||
requested: follow_state == "pending",
|
requested: follow_state == :follow_pending,
|
||||||
domain_blocking: User.blocks_domain?(reading_user, target),
|
domain_blocking: User.blocks_domain?(reading_user, target),
|
||||||
showing_reblogs:
|
showing_reblogs:
|
||||||
not UserRelationship.exists?(
|
not UserRelationship.exists?(
|
||||||
|
@ -190,11 +191,15 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
relationship =
|
relationship =
|
||||||
render("relationship.json", %{
|
if opts[:skip_relationships] do
|
||||||
user: opts[:for],
|
%{}
|
||||||
target: user,
|
else
|
||||||
relationships: opts[:relationships]
|
render("relationship.json", %{
|
||||||
})
|
user: opts[:for],
|
||||||
|
target: user,
|
||||||
|
relationships: opts[:relationships]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
%{
|
%{
|
||||||
id: to_string(user.id),
|
id: to_string(user.id),
|
||||||
|
|
|
@ -51,14 +51,15 @@ def render("index.json", %{notifications: notifications, for: reading_user} = op
|
||||||
|> Enum.filter(& &1)
|
|> Enum.filter(& &1)
|
||||||
|> Kernel.++(move_activities_targets)
|
|> Kernel.++(move_activities_targets)
|
||||||
|
|
||||||
UserRelationship.view_relationships_option(reading_user, actors)
|
UserRelationship.view_relationships_option(reading_user, actors,
|
||||||
|
source_mutes_only: opts[:skip_relationships]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
opts = %{
|
opts =
|
||||||
for: reading_user,
|
opts
|
||||||
parent_activities: parent_activities,
|
|> Map.put(:parent_activities, parent_activities)
|
||||||
relationships: relationships_opt
|
|> Map.put(:relationships, relationships_opt)
|
||||||
}
|
|
||||||
|
|
||||||
safe_render_many(notifications, NotificationView, "show.json", opts)
|
safe_render_many(notifications, NotificationView, "show.json", opts)
|
||||||
end
|
end
|
||||||
|
@ -82,12 +83,16 @@ def render(
|
||||||
|
|
||||||
mastodon_type = Activity.mastodon_notification_type(activity)
|
mastodon_type = Activity.mastodon_notification_type(activity)
|
||||||
|
|
||||||
|
render_opts = %{
|
||||||
|
relationships: opts[:relationships],
|
||||||
|
skip_relationships: opts[:skip_relationships]
|
||||||
|
}
|
||||||
|
|
||||||
with %{id: _} = account <-
|
with %{id: _} = account <-
|
||||||
AccountView.render("show.json", %{
|
AccountView.render(
|
||||||
user: actor,
|
"show.json",
|
||||||
for: reading_user,
|
Map.merge(render_opts, %{user: actor, for: reading_user})
|
||||||
relationships: opts[:relationships]
|
) do
|
||||||
}) do
|
|
||||||
response = %{
|
response = %{
|
||||||
id: to_string(notification.id),
|
id: to_string(notification.id),
|
||||||
type: mastodon_type,
|
type: mastodon_type,
|
||||||
|
@ -98,8 +103,6 @@ def render(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_opts = %{relationships: opts[:relationships]}
|
|
||||||
|
|
||||||
case mastodon_type do
|
case mastodon_type do
|
||||||
"mention" ->
|
"mention" ->
|
||||||
put_status(response, activity, reading_user, render_opts)
|
put_status(response, activity, reading_user, render_opts)
|
||||||
|
@ -111,6 +114,7 @@ def render(
|
||||||
put_status(response, parent_activity_fn.(), reading_user, render_opts)
|
put_status(response, parent_activity_fn.(), reading_user, render_opts)
|
||||||
|
|
||||||
"move" ->
|
"move" ->
|
||||||
|
# Note: :skip_relationships option being applied to _account_ rendering (here)
|
||||||
put_target(response, activity, reading_user, render_opts)
|
put_target(response, activity, reading_user, render_opts)
|
||||||
|
|
||||||
"follow" ->
|
"follow" ->
|
||||||
|
|
|
@ -99,7 +99,9 @@ def render("index.json", opts) do
|
||||||
true ->
|
true ->
|
||||||
actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
|
actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
|
||||||
|
|
||||||
UserRelationship.view_relationships_option(reading_user, actors)
|
UserRelationship.view_relationships_option(reading_user, actors,
|
||||||
|
source_mutes_only: opts[:skip_relationships]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
opts =
|
opts =
|
||||||
|
@ -153,7 +155,8 @@ def render(
|
||||||
AccountView.render("show.json", %{
|
AccountView.render("show.json", %{
|
||||||
user: user,
|
user: user,
|
||||||
for: opts[:for],
|
for: opts[:for],
|
||||||
relationships: opts[:relationships]
|
relationships: opts[:relationships],
|
||||||
|
skip_relationships: opts[:skip_relationships]
|
||||||
}),
|
}),
|
||||||
in_reply_to_id: nil,
|
in_reply_to_id: nil,
|
||||||
in_reply_to_account_id: nil,
|
in_reply_to_account_id: nil,
|
||||||
|
@ -301,6 +304,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
||||||
_ -> []
|
_ -> []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Status muted state (would do 1 request per status unless user mutes are preloaded)
|
||||||
muted =
|
muted =
|
||||||
thread_muted? ||
|
thread_muted? ||
|
||||||
UserRelationship.exists?(
|
UserRelationship.exists?(
|
||||||
|
@ -319,7 +323,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
||||||
AccountView.render("show.json", %{
|
AccountView.render("show.json", %{
|
||||||
user: user,
|
user: user,
|
||||||
for: opts[:for],
|
for: opts[:for],
|
||||||
relationships: opts[:relationships]
|
relationships: opts[:relationships],
|
||||||
|
skip_relationships: opts[:skip_relationships]
|
||||||
}),
|
}),
|
||||||
in_reply_to_id: reply_to && to_string(reply_to.id),
|
in_reply_to_id: reply_to && to_string(reply_to.id),
|
||||||
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
|
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper,
|
import Pleroma.Web.ControllerHelper,
|
||||||
only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
|
only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
|
||||||
|
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
@ -132,7 +132,12 @@ def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> put_view(StatusView)
|
|> put_view(StatusView)
|
||||||
|> render("index.json", activities: activities, for: for_user, as: :activity)
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: for_user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "POST /api/v1/pleroma/accounts/:id/subscribe"
|
@doc "POST /api/v1/pleroma/accounts/:id/subscribe"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
|
@ -110,12 +110,11 @@ def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id})
|
||||||
end
|
end
|
||||||
|
|
||||||
def conversation_statuses(
|
def conversation_statuses(
|
||||||
%{assigns: %{user: user}} = conn,
|
%{assigns: %{user: %{id: user_id} = user}} = conn,
|
||||||
%{"id" => participation_id} = params
|
%{"id" => participation_id} = params
|
||||||
) do
|
) do
|
||||||
with %Participation{} = participation <-
|
with %Participation{user_id: ^user_id} = participation <-
|
||||||
Participation.get(participation_id, preload: [:conversation]),
|
Participation.get(participation_id, preload: [:conversation]) do
|
||||||
true <- user.id == participation.user_id do
|
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|
@ -124,13 +123,19 @@ def conversation_statuses(
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
participation.conversation.ap_id
|
participation.conversation.ap_id
|
||||||
|> ActivityPub.fetch_activities_for_context(params)
|
|> ActivityPub.fetch_activities_for_context_query(params)
|
||||||
|
|> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities)
|
|> add_link_headers(activities)
|
||||||
|> put_view(StatusView)
|
|> put_view(StatusView)
|
||||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
|> render("index.json",
|
||||||
|
activities: activities,
|
||||||
|
for: user,
|
||||||
|
as: :activity,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
_error ->
|
_error ->
|
||||||
conn
|
conn
|
||||||
|
@ -184,13 +189,17 @@ def read_notification(%{assigns: %{user: user}} = conn, %{"id" => notification_i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
|
def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
|
||||||
with notifications <- Notification.set_read_up_to(user, max_id) do
|
with notifications <- Notification.set_read_up_to(user, max_id) do
|
||||||
notifications = Enum.take(notifications, 80)
|
notifications = Enum.take(notifications, 80)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(NotificationView)
|
|> put_view(NotificationView)
|
||||||
|> render("index.json", %{notifications: notifications, for: user})
|
|> render("index.json",
|
||||||
|
notifications: notifications,
|
||||||
|
for: user,
|
||||||
|
skip_relationships: skip_relationships?(params)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -64,5 +64,8 @@ def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) d
|
||||||
|
|
||||||
def fetch_data_for_activity(_), do: %{}
|
def fetch_data_for_activity(_), do: %{}
|
||||||
|
|
||||||
def perform(:fetch, %Activity{} = activity), do: fetch_data_for_activity(activity)
|
def perform(:fetch, %Activity{} = activity) do
|
||||||
|
fetch_data_for_activity(activity)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
4
mix.exs
4
mix.exs
|
@ -117,7 +117,7 @@ defp deps do
|
||||||
{:ecto_enum, "~> 1.4"},
|
{:ecto_enum, "~> 1.4"},
|
||||||
{:ecto_sql, "~> 3.3.2"},
|
{:ecto_sql, "~> 3.3.2"},
|
||||||
{:postgrex, ">= 0.13.5"},
|
{:postgrex, ">= 0.13.5"},
|
||||||
{:oban, "~> 0.12.1"},
|
{:oban, "~> 1.2"},
|
||||||
{:gettext, "~> 0.15"},
|
{:gettext, "~> 0.15"},
|
||||||
{:comeonin, "~> 4.1.1"},
|
{:comeonin, "~> 4.1.1"},
|
||||||
{:pbkdf2_elixir, "~> 0.12.3"},
|
{:pbkdf2_elixir, "~> 0.12.3"},
|
||||||
|
@ -183,7 +183,7 @@ defp deps do
|
||||||
{:flake_id, "~> 0.1.0"},
|
{:flake_id, "~> 0.1.0"},
|
||||||
{:remote_ip,
|
{:remote_ip,
|
||||||
git: "https://git.pleroma.social/pleroma/remote_ip.git",
|
git: "https://git.pleroma.social/pleroma/remote_ip.git",
|
||||||
ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"},
|
ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"},
|
||||||
{:captcha,
|
{:captcha,
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
||||||
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
|
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
|
||||||
|
|
8
mix.lock
8
mix.lock
|
@ -26,7 +26,7 @@
|
||||||
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
|
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
|
||||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
||||||
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
|
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
|
||||||
"ecto": {:hex, :ecto, "3.3.3", "0830bf3aebcbf3d8c1a1811cd581773b6866886c012f52c0f027031fa96a0b53", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "12e368e3c2a2938d7776defaabdae40e82900fc4d8d66120ec1e01dfd8b93c3a"},
|
"ecto": {:hex, :ecto, "3.4.0", "a7a83ab8359bf816ce729e5e65981ce25b9fc5adfc89c2ea3980f4fed0bfd7c1", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "5eed18252f5b5bbadec56a24112b531343507dbe046273133176b12190ce19cc"},
|
||||||
"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", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
"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", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 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", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
|
"ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 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", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
|
||||||
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
|
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
|
||||||
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
|
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
|
||||||
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
|
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
|
||||||
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
|
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
|
||||||
"joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"},
|
"joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"},
|
||||||
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
|
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
|
||||||
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
||||||
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
|
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
|
||||||
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
|
||||||
"oban": {:hex, :oban, "0.12.1", "695e9490c6e0edfca616d80639528e448bd29b3bff7b7dd10a56c79b00a5d7fb", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c1d58d69b8b5a86e7167abbb8cc92764a66f25f12f6172052595067fc6a30a17"},
|
"oban": {:hex, :oban, "1.2.0", "7cca94d341be43d220571e28f69131c4afc21095b25257397f50973d3fc59b07", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ba5f8b3f7d76967b3e23cf8014f6a13e4ccb33431e4808f036709a7f822362ee"},
|
||||||
"open_api_spex": {:hex, :open_api_spex, "3.6.0", "64205aba9f2607f71b08fd43e3351b9c5e9898ec5ef49fc0ae35890da502ade9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "126ba3473966277132079cb1d5bf1e3df9e36fe2acd00166e75fd125cecb59c5"},
|
"open_api_spex": {:hex, :open_api_spex, "3.6.0", "64205aba9f2607f71b08fd43e3351b9c5e9898ec5ef49fc0ae35890da502ade9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "126ba3473966277132079cb1d5bf1e3df9e36fe2acd00166e75fd125cecb59c5"},
|
||||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
||||||
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"},
|
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"},
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
"quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"},
|
"quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"},
|
||||||
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
|
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
|
||||||
"recon": {:hex, :recon, "2.5.0", "2f7fcbec2c35034bade2f9717f77059dc54eb4e929a3049ca7ba6775c0bd66cd", [:mix, :rebar3], [], "hexpm", "72f3840fedd94f06315c523f6cecf5b4827233bed7ae3fe135b2a0ebeab5e196"},
|
"recon": {:hex, :recon, "2.5.0", "2f7fcbec2c35034bade2f9717f77059dc54eb4e929a3049ca7ba6775c0bd66cd", [:mix, :rebar3], [], "hexpm", "72f3840fedd94f06315c523f6cecf5b4827233bed7ae3fe135b2a0ebeab5e196"},
|
||||||
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "825dc00aaba5a1b7c4202a532b696b595dd3bcb3", [ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"]},
|
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]},
|
||||||
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
|
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
|
||||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
|
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
|
||||||
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
|
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
|
||||||
|
|
|
@ -3,7 +3,6 @@ defmodule Pleroma.Repo.Migrations.MigrateOldBookmarks do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Bookmark
|
alias Pleroma.Bookmark
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
|
||||||
def up do
|
def up do
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule Pleroma.Repo.Migrations.CreateSafeJsonbSet do
|
defmodule Pleroma.Repo.Migrations.CreateSafeJsonbSet do
|
||||||
use Ecto.Migration
|
use Ecto.Migration
|
||||||
alias Pleroma.User
|
|
||||||
|
|
||||||
def change do
|
def change do
|
||||||
execute("""
|
execute("""
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.ChangeFollowingRelationshipsStateToInteger do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
@alter_following_relationship_state "ALTER TABLE following_relationships ALTER COLUMN state"
|
||||||
|
|
||||||
|
def up do
|
||||||
|
execute("""
|
||||||
|
#{@alter_following_relationship_state} TYPE integer USING
|
||||||
|
CASE
|
||||||
|
WHEN state = 'pending' THEN 1
|
||||||
|
WHEN state = 'accept' THEN 2
|
||||||
|
WHEN state = 'reject' THEN 3
|
||||||
|
ELSE 0
|
||||||
|
END;
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
execute("""
|
||||||
|
#{@alter_following_relationship_state} TYPE varchar(255) USING
|
||||||
|
CASE
|
||||||
|
WHEN state = 1 THEN 'pending'
|
||||||
|
WHEN state = 2 THEN 'accept'
|
||||||
|
WHEN state = 3 THEN 'reject'
|
||||||
|
ELSE ''
|
||||||
|
END;
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddFollowingRelationshipsFollowingIdIndex do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
# [:follower_index] index is useless because of [:follower_id, :following_id] index
|
||||||
|
# [:following_id] index makes sense because of user's followers-targeted queries
|
||||||
|
def change do
|
||||||
|
drop_if_exists(index(:following_relationships, [:follower_id]))
|
||||||
|
|
||||||
|
create_if_not_exists(index(:following_relationships, [:following_id]))
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.UpdateObanJobsTable do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
Oban.Migrations.up(version: 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
Oban.Migrations.down(version: 7)
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,28 +15,28 @@ defmodule Pleroma.FollowingRelationshipTest do
|
||||||
test "returns following addresses without internal.fetch" do
|
test "returns following addresses without internal.fetch" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
fetch_actor = InternalFetchActor.get_actor()
|
fetch_actor = InternalFetchActor.get_actor()
|
||||||
FollowingRelationship.follow(fetch_actor, user, "accept")
|
FollowingRelationship.follow(fetch_actor, user, :follow_accept)
|
||||||
assert FollowingRelationship.following(fetch_actor) == [user.follower_address]
|
assert FollowingRelationship.following(fetch_actor) == [user.follower_address]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns following addresses without relay" do
|
test "returns following addresses without relay" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
relay_actor = Relay.get_actor()
|
relay_actor = Relay.get_actor()
|
||||||
FollowingRelationship.follow(relay_actor, user, "accept")
|
FollowingRelationship.follow(relay_actor, user, :follow_accept)
|
||||||
assert FollowingRelationship.following(relay_actor) == [user.follower_address]
|
assert FollowingRelationship.following(relay_actor) == [user.follower_address]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns following addresses without remote user" do
|
test "returns following addresses without remote user" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
actor = insert(:user, local: false)
|
actor = insert(:user, local: false)
|
||||||
FollowingRelationship.follow(actor, user, "accept")
|
FollowingRelationship.follow(actor, user, :follow_accept)
|
||||||
assert FollowingRelationship.following(actor) == [user.follower_address]
|
assert FollowingRelationship.following(actor) == [user.follower_address]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns following addresses with local user" do
|
test "returns following addresses with local user" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
actor = insert(:user, local: true)
|
actor = insert(:user, local: true)
|
||||||
FollowingRelationship.follow(actor, user, "accept")
|
FollowingRelationship.follow(actor, user, :follow_accept)
|
||||||
|
|
||||||
assert FollowingRelationship.following(actor) == [
|
assert FollowingRelationship.following(actor) == [
|
||||||
actor.follower_address,
|
actor.follower_address,
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
defmodule Pleroma.Plugs.RateLimiterTest do
|
defmodule Pleroma.Plugs.RateLimiterTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Phoenix.ConnTest
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Plugs.RateLimiter
|
alias Pleroma.Plugs.RateLimiter
|
||||||
|
alias Plug.Conn
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
|
import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
|
||||||
|
@ -36,8 +38,15 @@ test "config is required for plug to work" do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it is disabled if it remote ip plug is enabled but no remote ip is found" do
|
test "it is disabled if it remote ip plug is enabled but no remote ip is found" do
|
||||||
Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
|
assert RateLimiter.disabled?(Conn.assign(build_conn(), :remote_ip_found, false))
|
||||||
assert RateLimiter.disabled?(Plug.Conn.assign(build_conn(), :remote_ip_found, false))
|
end
|
||||||
|
|
||||||
|
test "it is enabled if remote ip found" do
|
||||||
|
refute RateLimiter.disabled?(Conn.assign(build_conn(), :remote_ip_found, true))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it is enabled if remote_ip_found flag doesn't exist" do
|
||||||
|
refute RateLimiter.disabled?(build_conn())
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it restricts based on config values" do
|
test "it restricts based on config values" do
|
||||||
|
@ -58,7 +67,7 @@ test "it restricts based on config values" do
|
||||||
end
|
end
|
||||||
|
|
||||||
conn = RateLimiter.call(conn, plug_opts)
|
conn = RateLimiter.call(conn, plug_opts)
|
||||||
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
|
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
|
||||||
assert conn.halted
|
assert conn.halted
|
||||||
|
|
||||||
Process.sleep(50)
|
Process.sleep(50)
|
||||||
|
@ -68,7 +77,7 @@ test "it restricts based on config values" do
|
||||||
conn = RateLimiter.call(conn, plug_opts)
|
conn = RateLimiter.call(conn, plug_opts)
|
||||||
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
|
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
|
||||||
|
|
||||||
refute conn.status == Plug.Conn.Status.code(:too_many_requests)
|
refute conn.status == Conn.Status.code(:too_many_requests)
|
||||||
refute conn.resp_body
|
refute conn.resp_body
|
||||||
refute conn.halted
|
refute conn.halted
|
||||||
end
|
end
|
||||||
|
@ -98,7 +107,7 @@ test "`params` option allows different queries to be tracked independently" do
|
||||||
plug_opts = RateLimiter.init(name: limiter_name, params: ["id"])
|
plug_opts = RateLimiter.init(name: limiter_name, params: ["id"])
|
||||||
|
|
||||||
conn = build_conn(:get, "/?id=1")
|
conn = build_conn(:get, "/?id=1")
|
||||||
conn = Plug.Conn.fetch_query_params(conn)
|
conn = Conn.fetch_query_params(conn)
|
||||||
conn_2 = build_conn(:get, "/?id=2")
|
conn_2 = build_conn(:get, "/?id=2")
|
||||||
|
|
||||||
RateLimiter.call(conn, plug_opts)
|
RateLimiter.call(conn, plug_opts)
|
||||||
|
@ -119,7 +128,7 @@ test "it supports combination of options modifying bucket name" do
|
||||||
id = "100"
|
id = "100"
|
||||||
|
|
||||||
conn = build_conn(:get, "/?id=#{id}")
|
conn = build_conn(:get, "/?id=#{id}")
|
||||||
conn = Plug.Conn.fetch_query_params(conn)
|
conn = Conn.fetch_query_params(conn)
|
||||||
conn_2 = build_conn(:get, "/?id=#{101}")
|
conn_2 = build_conn(:get, "/?id=#{101}")
|
||||||
|
|
||||||
RateLimiter.call(conn, plug_opts)
|
RateLimiter.call(conn, plug_opts)
|
||||||
|
@ -147,13 +156,13 @@ test "are restricted based on remote IP" do
|
||||||
|
|
||||||
conn = RateLimiter.call(conn, plug_opts)
|
conn = RateLimiter.call(conn, plug_opts)
|
||||||
|
|
||||||
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
|
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
|
||||||
assert conn.halted
|
assert conn.halted
|
||||||
|
|
||||||
conn_2 = RateLimiter.call(conn_2, plug_opts)
|
conn_2 = RateLimiter.call(conn_2, plug_opts)
|
||||||
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
|
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
|
||||||
|
|
||||||
refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
|
refute conn_2.status == Conn.Status.code(:too_many_requests)
|
||||||
refute conn_2.resp_body
|
refute conn_2.resp_body
|
||||||
refute conn_2.halted
|
refute conn_2.halted
|
||||||
end
|
end
|
||||||
|
@ -187,7 +196,7 @@ test "can have limits separate from unauthenticated connections" do
|
||||||
|
|
||||||
conn = RateLimiter.call(conn, plug_opts)
|
conn = RateLimiter.call(conn, plug_opts)
|
||||||
|
|
||||||
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
|
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
|
||||||
assert conn.halted
|
assert conn.halted
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -210,12 +219,12 @@ test "different users are counted independently" do
|
||||||
end
|
end
|
||||||
|
|
||||||
conn = RateLimiter.call(conn, plug_opts)
|
conn = RateLimiter.call(conn, plug_opts)
|
||||||
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
|
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
|
||||||
assert conn.halted
|
assert conn.halted
|
||||||
|
|
||||||
conn_2 = RateLimiter.call(conn_2, plug_opts)
|
conn_2 = RateLimiter.call(conn_2, plug_opts)
|
||||||
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
|
assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
|
||||||
refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
|
refute conn_2.status == Conn.Status.code(:too_many_requests)
|
||||||
refute conn_2.resp_body
|
refute conn_2.resp_body
|
||||||
refute conn_2.halted
|
refute conn_2.halted
|
||||||
end
|
end
|
||||||
|
|
|
@ -140,7 +140,7 @@ test "no user to toggle" do
|
||||||
test "user is unsubscribed" do
|
test "user is unsubscribed" do
|
||||||
followed = insert(:user)
|
followed = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
User.follow(user, followed, "accept")
|
User.follow(user, followed, :follow_accept)
|
||||||
|
|
||||||
Mix.Tasks.Pleroma.User.run(["unsubscribe", user.nickname])
|
Mix.Tasks.Pleroma.User.run(["unsubscribe", user.nickname])
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,8 @@ test "doesn't return already accepted or duplicate follow requests" do
|
||||||
CommonAPI.follow(pending_follower, locked)
|
CommonAPI.follow(pending_follower, locked)
|
||||||
CommonAPI.follow(pending_follower, locked)
|
CommonAPI.follow(pending_follower, locked)
|
||||||
CommonAPI.follow(accepted_follower, locked)
|
CommonAPI.follow(accepted_follower, locked)
|
||||||
Pleroma.FollowingRelationship.update(accepted_follower, locked, "accept")
|
|
||||||
|
Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
|
||||||
|
|
||||||
assert [^pending_follower] = User.get_follow_requests(locked)
|
assert [^pending_follower] = User.get_follow_requests(locked)
|
||||||
end
|
end
|
||||||
|
@ -319,7 +320,7 @@ test "unfollow with syncronizes external user" do
|
||||||
following_address: "http://localhost:4001/users/fuser2/following"
|
following_address: "http://localhost:4001/users/fuser2/following"
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, user} = User.follow(user, followed, "accept")
|
{:ok, user} = User.follow(user, followed, :follow_accept)
|
||||||
|
|
||||||
{:ok, user, _activity} = User.unfollow(user, followed)
|
{:ok, user, _activity} = User.unfollow(user, followed)
|
||||||
|
|
||||||
|
@ -332,7 +333,7 @@ test "unfollow takes a user and another user" do
|
||||||
followed = insert(:user)
|
followed = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
{:ok, user} = User.follow(user, followed, "accept")
|
{:ok, user} = User.follow(user, followed, :follow_accept)
|
||||||
|
|
||||||
assert User.following(user) == [user.follower_address, followed.follower_address]
|
assert User.following(user) == [user.follower_address, followed.follower_address]
|
||||||
|
|
||||||
|
@ -353,7 +354,7 @@ test "unfollow doesn't unfollow yourself" do
|
||||||
test "test if a user is following another user" do
|
test "test if a user is following another user" do
|
||||||
followed = insert(:user)
|
followed = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
User.follow(user, followed, "accept")
|
User.follow(user, followed, :follow_accept)
|
||||||
|
|
||||||
assert User.following?(user, followed)
|
assert User.following?(user, followed)
|
||||||
refute User.following?(followed, user)
|
refute User.following?(followed, user)
|
||||||
|
@ -609,7 +610,7 @@ test "returns an ap_followers link for a user" do
|
||||||
) <> "/followers"
|
) <> "/followers"
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "remote user creation changeset" do
|
describe "remote user changeset" do
|
||||||
@valid_remote %{
|
@valid_remote %{
|
||||||
bio: "hello",
|
bio: "hello",
|
||||||
name: "Someone",
|
name: "Someone",
|
||||||
|
@ -621,28 +622,28 @@ test "returns an ap_followers link for a user" do
|
||||||
setup do: clear_config([:instance, :user_name_length])
|
setup do: clear_config([:instance, :user_name_length])
|
||||||
|
|
||||||
test "it confirms validity" do
|
test "it confirms validity" do
|
||||||
cs = User.remote_user_creation(@valid_remote)
|
cs = User.remote_user_changeset(@valid_remote)
|
||||||
assert cs.valid?
|
assert cs.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it sets the follower_adress" do
|
test "it sets the follower_adress" do
|
||||||
cs = User.remote_user_creation(@valid_remote)
|
cs = User.remote_user_changeset(@valid_remote)
|
||||||
# remote users get a fake local follower address
|
# remote users get a fake local follower address
|
||||||
assert cs.changes.follower_address ==
|
assert cs.changes.follower_address ==
|
||||||
User.ap_followers(%User{nickname: @valid_remote[:nickname]})
|
User.ap_followers(%User{nickname: @valid_remote[:nickname]})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it enforces the fqn format for nicknames" do
|
test "it enforces the fqn format for nicknames" do
|
||||||
cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
|
cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
|
||||||
assert Ecto.Changeset.get_field(cs, :local) == false
|
assert Ecto.Changeset.get_field(cs, :local) == false
|
||||||
assert cs.changes.avatar
|
assert cs.changes.avatar
|
||||||
refute cs.valid?
|
refute cs.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it has required fields" do
|
test "it has required fields" do
|
||||||
[:name, :ap_id]
|
[:ap_id]
|
||||||
|> Enum.each(fn field ->
|
|> Enum.each(fn field ->
|
||||||
cs = User.remote_user_creation(Map.delete(@valid_remote, field))
|
cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
|
||||||
refute cs.valid?
|
refute cs.valid?
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -1198,58 +1199,6 @@ test "get_public_key_for_ap_id fetches a user that's not in the db" do
|
||||||
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "insert or update a user from given data" do
|
|
||||||
test "with normal data" do
|
|
||||||
user = insert(:user, %{nickname: "nick@name.de"})
|
|
||||||
data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
|
|
||||||
|
|
||||||
assert {:ok, %User{}} = User.insert_or_update_user(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with overly long fields" do
|
|
||||||
current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255)
|
|
||||||
user = insert(:user, nickname: "nickname@supergood.domain")
|
|
||||||
|
|
||||||
data = %{
|
|
||||||
ap_id: user.ap_id,
|
|
||||||
name: user.name,
|
|
||||||
nickname: user.nickname,
|
|
||||||
fields: [
|
|
||||||
%{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
assert {:ok, %User{}} = User.insert_or_update_user(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with an overly long bio" do
|
|
||||||
current_max_length = Pleroma.Config.get([:instance, :user_bio_length], 5000)
|
|
||||||
user = insert(:user, nickname: "nickname@supergood.domain")
|
|
||||||
|
|
||||||
data = %{
|
|
||||||
ap_id: user.ap_id,
|
|
||||||
name: user.name,
|
|
||||||
nickname: user.nickname,
|
|
||||||
bio: String.duplicate("h", current_max_length + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert {:ok, %User{}} = User.insert_or_update_user(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with an overly long display name" do
|
|
||||||
current_max_length = Pleroma.Config.get([:instance, :user_name_length], 100)
|
|
||||||
user = insert(:user, nickname: "nickname@supergood.domain")
|
|
||||||
|
|
||||||
data = %{
|
|
||||||
ap_id: user.ap_id,
|
|
||||||
name: String.duplicate("h", current_max_length + 1),
|
|
||||||
nickname: user.nickname
|
|
||||||
}
|
|
||||||
|
|
||||||
assert {:ok, %User{}} = User.insert_or_update_user(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "per-user rich-text filtering" do
|
describe "per-user rich-text filtering" do
|
||||||
test "html_filter_policy returns default policies, when rich-text is enabled" do
|
test "html_filter_policy returns default policies, when rich-text is enabled" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -1239,16 +1239,56 @@ test "POST /api/ap/upload_media", %{conn: conn} do
|
||||||
filename: "an_image.jpg"
|
filename: "an_image.jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
conn =
|
object =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|
||||||
|
|> json_response(:created)
|
||||||
|
|
||||||
assert object = json_response(conn, :created)
|
|
||||||
assert object["name"] == desc
|
assert object["name"] == desc
|
||||||
assert object["type"] == "Document"
|
assert object["type"] == "Document"
|
||||||
assert object["actor"] == user.ap_id
|
assert object["actor"] == user.ap_id
|
||||||
|
assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"]
|
||||||
|
assert is_binary(object_href)
|
||||||
|
assert object_mediatype == "image/jpeg"
|
||||||
|
|
||||||
|
activity_request = %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"content" => "AP C2S test, attachment",
|
||||||
|
"attachment" => [object]
|
||||||
|
},
|
||||||
|
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"cc" => []
|
||||||
|
}
|
||||||
|
|
||||||
|
activity_response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/users/#{user.nickname}/outbox", activity_request)
|
||||||
|
|> json_response(:created)
|
||||||
|
|
||||||
|
assert activity_response["id"]
|
||||||
|
assert activity_response["object"]
|
||||||
|
assert activity_response["actor"] == user.ap_id
|
||||||
|
|
||||||
|
assert %Object{data: %{"attachment" => [attachment]}} =
|
||||||
|
Object.normalize(activity_response["object"])
|
||||||
|
|
||||||
|
assert attachment["type"] == "Document"
|
||||||
|
assert attachment["name"] == desc
|
||||||
|
|
||||||
|
assert [
|
||||||
|
%{
|
||||||
|
"href" => ^object_href,
|
||||||
|
"type" => "Link",
|
||||||
|
"mediaType" => ^object_mediatype
|
||||||
|
}
|
||||||
|
] = attachment["url"]
|
||||||
|
|
||||||
|
# Fails if unauthenticated
|
||||||
conn
|
conn
|
||||||
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|
|> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
|
||||||
|> json_response(403)
|
|> json_response(403)
|
||||||
|
|
|
@ -1230,19 +1230,13 @@ test "it remaps video URLs as attachments if necessary" do
|
||||||
attachment = %{
|
attachment = %{
|
||||||
"type" => "Link",
|
"type" => "Link",
|
||||||
"mediaType" => "video/mp4",
|
"mediaType" => "video/mp4",
|
||||||
"href" =>
|
|
||||||
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
|
|
||||||
"mimeType" => "video/mp4",
|
|
||||||
"size" => 5_015_880,
|
|
||||||
"url" => [
|
"url" => [
|
||||||
%{
|
%{
|
||||||
"href" =>
|
"href" =>
|
||||||
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
|
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
|
||||||
"mediaType" => "video/mp4",
|
"mediaType" => "video/mp4"
|
||||||
"type" => "Link"
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"width" => 480
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert object.data["url"] ==
|
assert object.data["url"] ==
|
||||||
|
@ -1624,7 +1618,7 @@ test "it upgrades a user to activitypub" do
|
||||||
})
|
})
|
||||||
|
|
||||||
user_two = insert(:user)
|
user_two = insert(:user)
|
||||||
Pleroma.FollowingRelationship.follow(user_two, user, "accept")
|
Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
|
||||||
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
|
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
|
||||||
|
@ -2063,11 +2057,7 @@ test "returns modified object when attachment is map" do
|
||||||
%{
|
%{
|
||||||
"mediaType" => "video/mp4",
|
"mediaType" => "video/mp4",
|
||||||
"url" => [
|
"url" => [
|
||||||
%{
|
%{"href" => "https://peertube.moe/stat-480.mp4", "mediaType" => "video/mp4"}
|
||||||
"href" => "https://peertube.moe/stat-480.mp4",
|
|
||||||
"mediaType" => "video/mp4",
|
|
||||||
"type" => "Link"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -2085,23 +2075,13 @@ test "returns modified object when attachment is list" do
|
||||||
%{
|
%{
|
||||||
"mediaType" => "video/mp4",
|
"mediaType" => "video/mp4",
|
||||||
"url" => [
|
"url" => [
|
||||||
%{
|
%{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"}
|
||||||
"href" => "https://pe.er/stat-480.mp4",
|
|
||||||
"mediaType" => "video/mp4",
|
|
||||||
"type" => "Link"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"href" => "https://pe.er/stat-480.mp4",
|
|
||||||
"mediaType" => "video/mp4",
|
"mediaType" => "video/mp4",
|
||||||
"mimeType" => "video/mp4",
|
|
||||||
"url" => [
|
"url" => [
|
||||||
%{
|
%{"href" => "https://pe.er/stat-480.mp4", "mediaType" => "video/mp4"}
|
||||||
"href" => "https://pe.er/stat-480.mp4",
|
|
||||||
"mediaType" => "video/mp4",
|
|
||||||
"type" => "Link"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,7 @@ test "Renders profile fields" do
|
||||||
|
|
||||||
{:ok, user} =
|
{:ok, user} =
|
||||||
insert(:user)
|
insert(:user)
|
||||||
|> User.upgrade_changeset(%{fields: fields})
|
|> User.update_changeset(%{fields: fields})
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
|
|
|
@ -2273,13 +2273,17 @@ test "saving full setting if value is in full_key_update list", %{conn: conn} do
|
||||||
value: :erlang.term_to_binary([])
|
value: :erlang.term_to_binary([])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Pleroma.Config.TransferTask.load_and_update_env([], false)
|
||||||
|
|
||||||
|
assert Application.get_env(:logger, :backends) == []
|
||||||
|
|
||||||
conn =
|
conn =
|
||||||
post(conn, "/api/pleroma/admin/config", %{
|
post(conn, "/api/pleroma/admin/config", %{
|
||||||
configs: [
|
configs: [
|
||||||
%{
|
%{
|
||||||
group: config.group,
|
group: config.group,
|
||||||
key: config.key,
|
key: config.key,
|
||||||
value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
|
value: [":console"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -2290,8 +2294,7 @@ test "saving full setting if value is in full_key_update list", %{conn: conn} do
|
||||||
"group" => ":logger",
|
"group" => ":logger",
|
||||||
"key" => ":backends",
|
"key" => ":backends",
|
||||||
"value" => [
|
"value" => [
|
||||||
":console",
|
":console"
|
||||||
%{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
|
|
||||||
],
|
],
|
||||||
"db" => [":backends"]
|
"db" => [":backends"]
|
||||||
}
|
}
|
||||||
|
@ -2299,14 +2302,8 @@ test "saving full setting if value is in full_key_update list", %{conn: conn} do
|
||||||
}
|
}
|
||||||
|
|
||||||
assert Application.get_env(:logger, :backends) == [
|
assert Application.get_env(:logger, :backends) == [
|
||||||
:console,
|
:console
|
||||||
{ExSyslogger, :ex_syslogger}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
capture_log(fn ->
|
|
||||||
require Logger
|
|
||||||
Logger.warn("Ooops...")
|
|
||||||
end) =~ "Ooops..."
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "saving full setting if value is not keyword", %{conn: conn} do
|
test "saving full setting if value is not keyword", %{conn: conn} do
|
||||||
|
|
|
@ -553,7 +553,7 @@ test "cancels a pending follow for a local user" do
|
||||||
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
||||||
CommonAPI.follow(follower, followed)
|
CommonAPI.follow(follower, followed)
|
||||||
|
|
||||||
assert User.get_follow_state(follower, followed) == "pending"
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
||||||
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
||||||
assert User.get_follow_state(follower, followed) == nil
|
assert User.get_follow_state(follower, followed) == nil
|
||||||
|
|
||||||
|
@ -575,7 +575,7 @@ test "cancels a pending follow for a remote user" do
|
||||||
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
|
||||||
CommonAPI.follow(follower, followed)
|
CommonAPI.follow(follower, followed)
|
||||||
|
|
||||||
assert User.get_follow_state(follower, followed) == "pending"
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
||||||
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
||||||
assert User.get_follow_state(follower, followed) == nil
|
assert User.get_follow_state(follower, followed) == nil
|
||||||
|
|
||||||
|
|
|
@ -6,20 +6,29 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ApiSpec
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
import OpenApiSpex.TestAssertions
|
||||||
|
|
||||||
test "blocking / unblocking a domain" do
|
test "blocking / unblocking a domain" do
|
||||||
%{user: user, conn: conn} = oauth_access(["write:blocks"])
|
%{user: user, conn: conn} = oauth_access(["write:blocks"])
|
||||||
other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
|
other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
|
||||||
|
|
||||||
ret_conn = post(conn, "/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
ret_conn =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
||||||
|
|
||||||
assert %{} = json_response(ret_conn, 200)
|
assert %{} = json_response(ret_conn, 200)
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
assert User.blocks?(user, other_user)
|
assert User.blocks?(user, other_user)
|
||||||
|
|
||||||
ret_conn = delete(conn, "/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
ret_conn =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
||||||
|
|
||||||
assert %{} = json_response(ret_conn, 200)
|
assert %{} = json_response(ret_conn, 200)
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
@ -41,5 +50,12 @@ test "getting a list of domain blocks" do
|
||||||
|
|
||||||
assert "bad.site" in domain_blocks
|
assert "bad.site" in domain_blocks
|
||||||
assert "even.worse.site" in domain_blocks
|
assert "even.worse.site" in domain_blocks
|
||||||
|
assert_schema(domain_blocks, "DomainBlocksResponse", ApiSpec.spec())
|
||||||
|
end
|
||||||
|
|
||||||
|
test "DomainBlocksResponse example matches schema" do
|
||||||
|
api_spec = ApiSpec.spec()
|
||||||
|
schema = DomainBlocksResponse.schema()
|
||||||
|
assert_schema(schema.example, "DomainBlocksResponse", api_spec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ test "/api/v1/follow_requests works", %{user: user, conn: conn} do
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, _activity} = ActivityPub.follow(other_user, user)
|
{:ok, _activity} = ActivityPub.follow(other_user, user)
|
||||||
{:ok, other_user} = User.follow(other_user, user, "pending")
|
{:ok, other_user} = User.follow(other_user, user, :follow_pending)
|
||||||
|
|
||||||
assert User.following?(other_user, user) == false
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, _activity} = ActivityPub.follow(other_user, user)
|
{:ok, _activity} = ActivityPub.follow(other_user, user)
|
||||||
{:ok, other_user} = User.follow(other_user, user, "pending")
|
{:ok, other_user} = User.follow(other_user, user, :follow_pending)
|
||||||
|
|
||||||
user = User.get_cached_by_id(user.id)
|
user = User.get_cached_by_id(user.id)
|
||||||
other_user = User.get_cached_by_id(other_user.id)
|
other_user = User.get_cached_by_id(other_user.id)
|
||||||
|
|
|
@ -12,6 +12,26 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
test "does NOT render account/pleroma/relationship if this is disabled by default" do
|
||||||
|
clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
|
||||||
|
|
||||||
|
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
|
||||||
|
{:ok, [_notification]} = Notification.create_notifications(activity)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/notifications")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert Enum.all?(response, fn n ->
|
||||||
|
get_in(n, ["account", "pleroma", "relationship"]) == %{}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
test "list of notifications" do
|
test "list of notifications" do
|
||||||
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
|
@ -1047,6 +1047,8 @@ test "replaces missing description with an empty string", %{conn: conn, user: us
|
||||||
end
|
end
|
||||||
|
|
||||||
test "bookmarks" do
|
test "bookmarks" do
|
||||||
|
bookmarks_uri = "/api/v1/bookmarks?with_relationships=true"
|
||||||
|
|
||||||
%{conn: conn} = oauth_access(["write:bookmarks", "read:bookmarks"])
|
%{conn: conn} = oauth_access(["write:bookmarks", "read:bookmarks"])
|
||||||
author = insert(:user)
|
author = insert(:user)
|
||||||
|
|
||||||
|
@ -1068,7 +1070,7 @@ test "bookmarks" do
|
||||||
|
|
||||||
assert json_response(response2, 200)["bookmarked"] == true
|
assert json_response(response2, 200)["bookmarked"] == true
|
||||||
|
|
||||||
bookmarks = get(conn, "/api/v1/bookmarks")
|
bookmarks = get(conn, bookmarks_uri)
|
||||||
|
|
||||||
assert [json_response(response2, 200), json_response(response1, 200)] ==
|
assert [json_response(response2, 200), json_response(response1, 200)] ==
|
||||||
json_response(bookmarks, 200)
|
json_response(bookmarks, 200)
|
||||||
|
@ -1077,7 +1079,7 @@ test "bookmarks" do
|
||||||
|
|
||||||
assert json_response(response1, 200)["bookmarked"] == false
|
assert json_response(response1, 200)["bookmarked"] == false
|
||||||
|
|
||||||
bookmarks = get(conn, "/api/v1/bookmarks")
|
bookmarks = get(conn, bookmarks_uri)
|
||||||
|
|
||||||
assert [json_response(response2, 200)] == json_response(bookmarks, 200)
|
assert [json_response(response2, 200)] == json_response(bookmarks, 200)
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,30 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|
||||||
describe "home" do
|
describe "home" do
|
||||||
setup do: oauth_access(["read:statuses"])
|
setup do: oauth_access(["read:statuses"])
|
||||||
|
|
||||||
|
test "does NOT render account/pleroma/relationship if this is disabled by default", %{
|
||||||
|
user: user,
|
||||||
|
conn: conn
|
||||||
|
} do
|
||||||
|
clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
|
||||||
|
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/timelines/home")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert Enum.all?(response, fn n ->
|
||||||
|
get_in(n, ["account", "pleroma", "relationship"]) == %{}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
test "the home timeline", %{user: user, conn: conn} do
|
test "the home timeline", %{user: user, conn: conn} do
|
||||||
|
uri = "/api/v1/timelines/home?with_relationships=true"
|
||||||
|
|
||||||
following = insert(:user, nickname: "followed")
|
following = insert(:user, nickname: "followed")
|
||||||
third_user = insert(:user, nickname: "repeated")
|
third_user = insert(:user, nickname: "repeated")
|
||||||
|
|
||||||
|
@ -28,13 +51,13 @@ test "the home timeline", %{user: user, conn: conn} do
|
||||||
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "repeated post"})
|
{:ok, activity} = CommonAPI.post(third_user, %{"status" => "repeated post"})
|
||||||
{:ok, _, _} = CommonAPI.repeat(activity.id, following)
|
{:ok, _, _} = CommonAPI.repeat(activity.id, following)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/v1/timelines/home")
|
ret_conn = get(conn, uri)
|
||||||
|
|
||||||
assert Enum.empty?(json_response(ret_conn, :ok))
|
assert Enum.empty?(json_response(ret_conn, :ok))
|
||||||
|
|
||||||
{:ok, _user} = User.follow(user, following)
|
{:ok, _user} = User.follow(user, following)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/v1/timelines/home")
|
ret_conn = get(conn, uri)
|
||||||
|
|
||||||
assert [
|
assert [
|
||||||
%{
|
%{
|
||||||
|
@ -59,7 +82,7 @@ test "the home timeline", %{user: user, conn: conn} do
|
||||||
|
|
||||||
{:ok, _user} = User.follow(third_user, user)
|
{:ok, _user} = User.follow(third_user, user)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/v1/timelines/home")
|
ret_conn = get(conn, uri)
|
||||||
|
|
||||||
assert [
|
assert [
|
||||||
%{
|
%{
|
||||||
|
|
|
@ -169,6 +169,23 @@ test "/api/v1/pleroma/conversations/:id/statuses" do
|
||||||
id_one = activity.id
|
id_one = activity.id
|
||||||
id_two = activity_two.id
|
id_two = activity_two.id
|
||||||
assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result
|
assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result
|
||||||
|
|
||||||
|
{:ok, %{id: id_three}} =
|
||||||
|
CommonAPI.post(other_user, %{
|
||||||
|
"status" => "Bye!",
|
||||||
|
"in_reply_to_status_id" => activity.id,
|
||||||
|
"in_reply_to_conversation_id" => participation.id
|
||||||
|
})
|
||||||
|
|
||||||
|
assert [%{"id" => ^id_two}, %{"id" => ^id_three}] =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2")
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert [%{"id" => ^id_three}] =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}")
|
||||||
|
|> json_response(:ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "PATCH /api/v1/pleroma/conversations/:id" do
|
test "PATCH /api/v1/pleroma/conversations/:id" do
|
||||||
|
|
|
@ -209,7 +209,7 @@ test "it doesn't send to user if recipients invalid and thread containment is en
|
||||||
Pleroma.Config.put([:instance, :skip_thread_containment], false)
|
Pleroma.Config.put([:instance, :skip_thread_containment], false)
|
||||||
author = insert(:user)
|
author = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
User.follow(user, author, "accept")
|
User.follow(user, author, :follow_accept)
|
||||||
|
|
||||||
activity =
|
activity =
|
||||||
insert(:note_activity,
|
insert(:note_activity,
|
||||||
|
@ -232,7 +232,7 @@ test "it sends message if recipients invalid and thread containment is disabled"
|
||||||
Pleroma.Config.put([:instance, :skip_thread_containment], true)
|
Pleroma.Config.put([:instance, :skip_thread_containment], true)
|
||||||
author = insert(:user)
|
author = insert(:user)
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
User.follow(user, author, "accept")
|
User.follow(user, author, :follow_accept)
|
||||||
|
|
||||||
activity =
|
activity =
|
||||||
insert(:note_activity,
|
insert(:note_activity,
|
||||||
|
@ -255,7 +255,7 @@ test "it sends message if recipients invalid and thread containment is enabled b
|
||||||
Pleroma.Config.put([:instance, :skip_thread_containment], false)
|
Pleroma.Config.put([:instance, :skip_thread_containment], false)
|
||||||
author = insert(:user)
|
author = insert(:user)
|
||||||
user = insert(:user, skip_thread_containment: true)
|
user = insert(:user, skip_thread_containment: true)
|
||||||
User.follow(user, author, "accept")
|
User.follow(user, author, :follow_accept)
|
||||||
|
|
||||||
activity =
|
activity =
|
||||||
insert(:note_activity,
|
insert(:note_activity,
|
||||||
|
|
Loading…
Reference in a new issue