Merge branch 'develop' into global-status-expiration
This commit is contained in:
commit
c56c0a3d23
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
|
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma won’t start. For hackney OTP update is not required.
|
||||||
- Mix task to create trusted OAuth App.
|
- Mix task to create trusted OAuth App.
|
||||||
- Notifications: Added `follow_request` notification type (configurable, see `[:notifications, :enable_follow_request_notifications]` setting).
|
- Notifications: Added `follow_request` notification type (configurable, see `[:notifications, :enable_follow_request_notifications]` setting).
|
||||||
|
- Added `:reject_deletes` group to SimplePolicy
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
|
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
|
||||||
|
@ -23,6 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Support pagination in conversations API
|
- Support pagination in conversations API
|
||||||
|
- **Breaking**: SimplePolicy `:reject` and `:accept` allow deletions again
|
||||||
|
- Fix follower/blocks import when nicknames starts with @
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- MFR policy to set global expiration for all local Create activities
|
- MFR policy to set global expiration for all local Create activities
|
||||||
|
|
|
@ -336,7 +336,8 @@
|
||||||
reject: [],
|
reject: [],
|
||||||
accept: [],
|
accept: [],
|
||||||
avatar_removal: [],
|
avatar_removal: [],
|
||||||
banner_removal: []
|
banner_removal: [],
|
||||||
|
reject_deletes: []
|
||||||
|
|
||||||
config :pleroma, :mrf_keyword,
|
config :pleroma, :mrf_keyword,
|
||||||
reject: [],
|
reject: [],
|
||||||
|
|
|
@ -1317,13 +1317,13 @@
|
||||||
%{
|
%{
|
||||||
key: :reject,
|
key: :reject,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "List of instances to reject any activities from",
|
description: "List of instances to reject activities from (except deletes)",
|
||||||
suggestions: ["example.com", "*.example.com"]
|
suggestions: ["example.com", "*.example.com"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :accept,
|
key: :accept,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "List of instances to accept any activities from",
|
description: "List of instances to only accept activities from (except deletes)",
|
||||||
suggestions: ["example.com", "*.example.com"]
|
suggestions: ["example.com", "*.example.com"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1343,6 +1343,12 @@
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "List of instances to strip banners from",
|
description: "List of instances to strip banners from",
|
||||||
suggestions: ["example.com", "*.example.com"]
|
suggestions: ["example.com", "*.example.com"]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :reject_deletes,
|
||||||
|
type: {:list, :string},
|
||||||
|
description: "List of instances to reject deletions from",
|
||||||
|
suggestions: ["example.com", "*.example.com"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,6 +49,7 @@ Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_si
|
||||||
* `banner_removal`: Banner images from these servers will be stripped from incoming messages.
|
* `banner_removal`: Banner images from these servers will be stripped from incoming messages.
|
||||||
* `report_removal`: Servers in this group will have their reports (flags) rejected.
|
* `report_removal`: Servers in this group will have their reports (flags) rejected.
|
||||||
* `federated_timeline_removal`: Servers in this group will have their messages unlisted from the public timelines by flipping the `to` and `cc` fields.
|
* `federated_timeline_removal`: Servers in this group will have their messages unlisted from the public timelines by flipping the `to` and `cc` fields.
|
||||||
|
* `reject_deletes`: Deletion requests will be rejected from these servers.
|
||||||
|
|
||||||
Servers should be configured as lists.
|
Servers should be configured as lists.
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,9 @@ This guide will assume you are on Debian Stretch. This guide should also work wi
|
||||||
|
|
||||||
* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/))
|
* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/))
|
||||||
* `postgresql-contrib` (9.6+, same situtation as above)
|
* `postgresql-contrib` (9.6+, same situtation as above)
|
||||||
* `elixir` (1.5+, [install from here, Debian and Ubuntu ship older versions](https://elixir-lang.org/install.html#unix-and-unix-like) or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
|
* `elixir` (1.8+, Follow the guide to install from the Erlang Solutions repo or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
|
||||||
* `erlang-dev`
|
* `erlang-dev`
|
||||||
* `erlang-tools`
|
* `erlang-nox`
|
||||||
* `erlang-parsetools`
|
|
||||||
* `erlang-eldap`, if you want to enable ldap authenticator
|
|
||||||
* `erlang-ssh`
|
|
||||||
* `erlang-xmerl`
|
|
||||||
* `git`
|
* `git`
|
||||||
* `build-essential`
|
* `build-essential`
|
||||||
|
|
||||||
|
@ -50,7 +46,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh
|
sudo apt install elixir erlang-dev erlang-nox
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install PleromaBE
|
### Install PleromaBE
|
||||||
|
|
|
@ -10,21 +10,17 @@
|
||||||
### 必要なソフトウェア
|
### 必要なソフトウェア
|
||||||
|
|
||||||
- PostgreSQL 9.6以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください)
|
- PostgreSQL 9.6以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください)
|
||||||
- postgresql-contrib 9.6以上 (同上)
|
- `postgresql-contrib` 9.6以上 (同上)
|
||||||
- Elixir 1.5 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
|
- Elixir 1.8 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
|
||||||
- erlang-dev
|
- `erlang-dev`
|
||||||
- erlang-tools
|
- `erlang-nox`
|
||||||
- erlang-parsetools
|
- `git`
|
||||||
- erlang-eldap (LDAP認証を有効化するときのみ必要)
|
- `build-essential`
|
||||||
- erlang-ssh
|
|
||||||
- erlang-xmerl
|
|
||||||
- git
|
|
||||||
- build-essential
|
|
||||||
|
|
||||||
#### このガイドで利用している追加パッケージ
|
#### このガイドで利用している追加パッケージ
|
||||||
|
|
||||||
- nginx (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください)
|
- `nginx` (おすすめです。他のリバースプロキシを使う場合は、参考となる設定をこのリポジトリから探してください)
|
||||||
- certbot (または何らかのLet's Encrypt向けACMEクライアント)
|
- `certbot` (または何らかのLet's Encrypt向けACMEクライアント)
|
||||||
|
|
||||||
### システムを準備する
|
### システムを準備する
|
||||||
|
|
||||||
|
@ -51,7 +47,7 @@ sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
|
||||||
* ElixirとErlangをインストールします、
|
* ElixirとErlangをインストールします、
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools erlang-ssh
|
sudo apt install elixir erlang-dev erlang-nox
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pleroma BE (バックエンド) をインストールします
|
### Pleroma BE (バックエンド) をインストールします
|
||||||
|
|
|
@ -47,7 +47,7 @@ defp filter(configs) do
|
||||||
@spec filter_group(atom(), keyword()) :: keyword()
|
@spec filter_group(atom(), keyword()) :: keyword()
|
||||||
def filter_group(group, configs) do
|
def filter_group(group, configs) do
|
||||||
Enum.reject(configs[group], fn {key, _v} ->
|
Enum.reject(configs[group], fn {key, _v} ->
|
||||||
key in @reject_keys or (group == :phoenix and key == :serve_endpoints)
|
key in @reject_keys or (group == :phoenix and key == :serve_endpoints) or group == :postgrex
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,14 +46,6 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
|
||||||
with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
|
with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
|
||||||
# We need to restart applications for loaded settings take effect
|
# We need to restart applications for loaded settings take effect
|
||||||
|
|
||||||
# TODO: some problem with prometheus after restart!
|
|
||||||
reject_restart =
|
|
||||||
if restart_pleroma? do
|
|
||||||
[nil, :prometheus]
|
|
||||||
else
|
|
||||||
[:pleroma, nil, :prometheus]
|
|
||||||
end
|
|
||||||
|
|
||||||
{logger, other} =
|
{logger, other} =
|
||||||
(Repo.all(ConfigDB) ++ deleted_settings)
|
(Repo.all(ConfigDB) ++ deleted_settings)
|
||||||
|> Enum.map(&transform_and_merge/1)
|
|> Enum.map(&transform_and_merge/1)
|
||||||
|
@ -65,10 +57,20 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
|
||||||
|
|
||||||
started_applications = Application.started_applications()
|
started_applications = Application.started_applications()
|
||||||
|
|
||||||
|
# TODO: some problem with prometheus after restart!
|
||||||
|
reject = [nil, :prometheus, :postgrex]
|
||||||
|
|
||||||
|
reject =
|
||||||
|
if restart_pleroma? do
|
||||||
|
reject
|
||||||
|
else
|
||||||
|
[:pleroma | reject]
|
||||||
|
end
|
||||||
|
|
||||||
other
|
other
|
||||||
|> Enum.map(&update/1)
|
|> Enum.map(&update/1)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|> Enum.reject(&(&1 in reject_restart))
|
|> Enum.reject(&(&1 in reject))
|
||||||
|> maybe_set_pleroma_last()
|
|> maybe_set_pleroma_last()
|
||||||
|> Enum.each(&restart(started_applications, &1, Config.get(:env)))
|
|> Enum.each(&restart(started_applications, &1, Config.get(:env)))
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,7 @@ def decrease_replies_count(ap_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def increase_vote_count(ap_id, name) do
|
def increase_vote_count(ap_id, name, actor) do
|
||||||
with %Object{} = object <- Object.normalize(ap_id),
|
with %Object{} = object <- Object.normalize(ap_id),
|
||||||
"Question" <- object.data["type"] do
|
"Question" <- object.data["type"] do
|
||||||
multiple = Map.has_key?(object.data, "anyOf")
|
multiple = Map.has_key?(object.data, "anyOf")
|
||||||
|
@ -276,12 +276,15 @@ def increase_vote_count(ap_id, name) do
|
||||||
option
|
option
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
voters = [actor | object.data["voters"] || []] |> Enum.uniq()
|
||||||
|
|
||||||
data =
|
data =
|
||||||
if multiple do
|
if multiple do
|
||||||
Map.put(object.data, "anyOf", options)
|
Map.put(object.data, "anyOf", options)
|
||||||
else
|
else
|
||||||
Map.put(object.data, "oneOf", options)
|
Map.put(object.data, "oneOf", options)
|
||||||
end
|
end
|
||||||
|
|> Map.put("voters", voters)
|
||||||
|
|
||||||
object
|
object
|
||||||
|> Object.change(%{data: data})
|
|> Object.change(%{data: data})
|
||||||
|
|
|
@ -45,11 +45,11 @@ def get_peers do
|
||||||
end
|
end
|
||||||
|
|
||||||
def init(_args) do
|
def init(_args) do
|
||||||
{:ok, get_stat_data()}
|
{:ok, calculate_stat_data()}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_call(:force_update, _from, _state) do
|
def handle_call(:force_update, _from, _state) do
|
||||||
new_stats = get_stat_data()
|
new_stats = calculate_stat_data()
|
||||||
{:reply, new_stats, new_stats}
|
{:reply, new_stats, new_stats}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@ def handle_call(:get_state, _from, state) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast(:run_update, _state) do
|
def handle_cast(:run_update, _state) do
|
||||||
new_stats = get_stat_data()
|
new_stats = calculate_stat_data()
|
||||||
|
|
||||||
{:noreply, new_stats}
|
{:noreply, new_stats}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_stat_data do
|
def calculate_stat_data do
|
||||||
peers =
|
peers =
|
||||||
from(
|
from(
|
||||||
u in User,
|
u in User,
|
||||||
|
@ -77,7 +77,15 @@ defp get_stat_data do
|
||||||
|
|
||||||
status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count)
|
status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count)
|
||||||
|
|
||||||
user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id)
|
users_query =
|
||||||
|
from(u in User,
|
||||||
|
where: u.deactivated != true,
|
||||||
|
where: u.local == true,
|
||||||
|
where: not is_nil(u.nickname),
|
||||||
|
where: not u.invisible
|
||||||
|
)
|
||||||
|
|
||||||
|
user_count = Repo.aggregate(users_query, :count, :id)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
peers: peers,
|
peers: peers,
|
||||||
|
|
|
@ -1180,7 +1180,9 @@ def get_users_from_set(ap_ids, local_only \\ true) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_recipients_from_activity(Activity.t()) :: [User.t()]
|
@spec get_recipients_from_activity(Activity.t()) :: [User.t()]
|
||||||
def get_recipients_from_activity(%Activity{recipients: to}) do
|
def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do
|
||||||
|
to = [actor | to]
|
||||||
|
|
||||||
User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false})
|
User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false})
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,9 +119,10 @@ def decrease_replies_count_if_reply(_object), do: :noop
|
||||||
|
|
||||||
def increase_poll_votes_if_vote(%{
|
def increase_poll_votes_if_vote(%{
|
||||||
"object" => %{"inReplyTo" => reply_ap_id, "name" => name},
|
"object" => %{"inReplyTo" => reply_ap_id, "name" => name},
|
||||||
"type" => "Create"
|
"type" => "Create",
|
||||||
|
"actor" => actor
|
||||||
}) do
|
}) do
|
||||||
Object.increase_vote_count(reply_ap_id, name)
|
Object.increase_vote_count(reply_ap_id, name, actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
def increase_poll_votes_if_vote(_create_data), do: :noop
|
def increase_poll_votes_if_vote(_create_data), do: :noop
|
||||||
|
@ -408,36 +409,6 @@ defp do_unreact_with_emoji(user, reaction_id, options) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
|
|
||||||
@spec like(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
|
||||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
|
||||||
def like(user, object, activity_id \\ nil, local \\ true) do
|
|
||||||
with {:ok, result} <- Repo.transaction(fn -> do_like(user, object, activity_id, local) end) do
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp do_like(
|
|
||||||
%User{ap_id: ap_id} = user,
|
|
||||||
%Object{data: %{"id" => _}} = object,
|
|
||||||
activity_id,
|
|
||||||
local
|
|
||||||
) do
|
|
||||||
with nil <- get_existing_like(ap_id, object),
|
|
||||||
like_data <- make_like_data(user, object, activity_id),
|
|
||||||
{:ok, activity} <- insert(like_data, local),
|
|
||||||
{:ok, object} <- add_like_to_object(activity, object),
|
|
||||||
:ok <- maybe_federate(activity) do
|
|
||||||
{:ok, activity, object}
|
|
||||||
else
|
|
||||||
%Activity{} = activity ->
|
|
||||||
{:ok, activity, object}
|
|
||||||
|
|
||||||
{:error, error} ->
|
|
||||||
Repo.rollback(error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec unlike(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
@spec unlike(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
||||||
{:ok, Activity.t(), Activity.t(), Object.t()} | {:ok, Object.t()} | {:error, any()}
|
{:ok, Activity.t(), Activity.t(), Object.t()} | {:ok, Object.t()} | {:error, any()}
|
||||||
def unlike(%User{} = actor, %Object{} = object, activity_id \\ nil, local \\ true) do
|
def unlike(%User{} = actor, %Object{} = object, activity_id \\ nil, local \\ true) do
|
||||||
|
|
|
@ -12,8 +12,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
alias Pleroma.Plugs.EnsureAuthenticatedPlug
|
alias Pleroma.Plugs.EnsureAuthenticatedPlug
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||||
alias Pleroma.Web.ActivityPub.ObjectView
|
alias Pleroma.Web.ActivityPub.ObjectView
|
||||||
|
alias Pleroma.Web.ActivityPub.Pipeline
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
alias Pleroma.Web.ActivityPub.UserView
|
alias Pleroma.Web.ActivityPub.UserView
|
||||||
|
@ -421,7 +423,10 @@ defp handle_user_activity(%User{} = user, %{"type" => "Delete"} = params) do
|
||||||
|
|
||||||
defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do
|
defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do
|
||||||
with %Object{} = object <- Object.normalize(params["object"]),
|
with %Object{} = object <- Object.normalize(params["object"]),
|
||||||
{:ok, activity, _object} <- ActivityPub.like(user, object) do
|
{_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
|
||||||
|
{_, {:ok, %Activity{} = activity, _meta}} <-
|
||||||
|
{:common_pipeline,
|
||||||
|
Pipeline.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
_ -> {:error, dgettext("errors", "Can't like object")}
|
_ -> {:error, dgettext("errors", "Can't like object")}
|
||||||
|
|
|
@ -148,6 +148,21 @@ defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image
|
||||||
|
|
||||||
defp check_banner_removal(_actor_info, object), do: {:ok, object}
|
defp check_banner_removal(_actor_info, object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
||||||
|
%{host: actor_host} = URI.parse(actor)
|
||||||
|
|
||||||
|
reject_deletes =
|
||||||
|
Pleroma.Config.get([:mrf_simple, :reject_deletes])
|
||||||
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
|
if MRF.subdomain_match?(reject_deletes, actor_host) do
|
||||||
|
{:reject, nil}
|
||||||
|
else
|
||||||
|
{:ok, object}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"actor" => actor} = object) do
|
def filter(%{"actor" => actor} = object) do
|
||||||
actor_info = URI.parse(actor)
|
actor_info = URI.parse(actor)
|
||||||
|
|
|
@ -15,12 +15,17 @@ def handle(object, meta \\ [])
|
||||||
# - Add like to object
|
# - Add like to object
|
||||||
# - Set up notification
|
# - Set up notification
|
||||||
def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
|
{:ok, result} =
|
||||||
|
Pleroma.Repo.transaction(fn ->
|
||||||
liked_object = Object.get_by_ap_id(object.data["object"])
|
liked_object = Object.get_by_ap_id(object.data["object"])
|
||||||
Utils.add_like_to_object(object, liked_object)
|
Utils.add_like_to_object(object, liked_object)
|
||||||
|
|
||||||
Notification.create_notifications(object)
|
Notification.create_notifications(object)
|
||||||
|
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
end)
|
||||||
|
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 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.CustomEmojiOperation do
|
||||||
|
alias OpenApiSpex.Operation
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
|
||||||
|
|
||||||
|
def open_api_operation(action) do
|
||||||
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
|
apply(__MODULE__, operation, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def index_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["custom_emojis"],
|
||||||
|
summary: "List custom custom emojis",
|
||||||
|
description: "Returns custom emojis that are available on the server.",
|
||||||
|
operationId: "CustomEmojiController.index",
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Custom Emojis", "application/json", CustomEmojisResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,30 @@
|
||||||
|
# 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.CustomEmoji do
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "CustomEmoji",
|
||||||
|
description: "Response schema for an CustomEmoji",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
shortcode: %Schema{type: :string},
|
||||||
|
url: %Schema{type: :string},
|
||||||
|
static_url: %Schema{type: :string},
|
||||||
|
visible_in_picker: %Schema{type: :boolean},
|
||||||
|
category: %Schema{type: :string},
|
||||||
|
tags: %Schema{type: :array}
|
||||||
|
},
|
||||||
|
example: %{
|
||||||
|
"shortcode" => "aaaa",
|
||||||
|
"url" => "https://files.mastodon.social/custom_emojis/images/000/007/118/original/aaaa.png",
|
||||||
|
"static_url" =>
|
||||||
|
"https://files.mastodon.social/custom_emojis/images/000/007/118/static/aaaa.png",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
|
@ -0,0 +1,42 @@
|
||||||
|
# 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.CustomEmojisResponse do
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
|
||||||
|
|
||||||
|
require OpenApiSpex
|
||||||
|
|
||||||
|
OpenApiSpex.schema(%{
|
||||||
|
title: "CustomEmojisResponse",
|
||||||
|
description: "Response schema for custom emojis",
|
||||||
|
type: :array,
|
||||||
|
items: CustomEmoji,
|
||||||
|
example: [
|
||||||
|
%{
|
||||||
|
"category" => "Fun",
|
||||||
|
"shortcode" => "blank",
|
||||||
|
"static_url" => "https://lain.com/emoji/blank.png",
|
||||||
|
"tags" => ["Fun"],
|
||||||
|
"url" => "https://lain.com/emoji/blank.png",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"category" => "Gif,Fun",
|
||||||
|
"shortcode" => "firefox",
|
||||||
|
"static_url" => "https://lain.com/emoji/Firefox.gif",
|
||||||
|
"tags" => ["Gif", "Fun"],
|
||||||
|
"url" => "https://lain.com/emoji/Firefox.gif",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"category" => "pack:mixed",
|
||||||
|
"shortcode" => "sadcat",
|
||||||
|
"static_url" => "https://lain.com/emoji/mixed/sadcat.png",
|
||||||
|
"tags" => ["pack:mixed"],
|
||||||
|
"url" => "https://lain.com/emoji/mixed/sadcat.png",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
end
|
|
@ -86,8 +86,9 @@ def delete(activity_id, user) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def repeat(id_or_ap_id, user, params \\ %{}) do
|
def repeat(id, user, params \\ %{}) do
|
||||||
with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)},
|
with {_, %Activity{data: %{"type" => "Create"}} = activity} <-
|
||||||
|
{:find_activity, Activity.get_by_id(id)},
|
||||||
object <- Object.normalize(activity),
|
object <- Object.normalize(activity),
|
||||||
announce_activity <- Utils.get_existing_announce(user.ap_id, object),
|
announce_activity <- Utils.get_existing_announce(user.ap_id, object),
|
||||||
public <- public_announce?(object, params) do
|
public <- public_announce?(object, params) do
|
||||||
|
@ -102,8 +103,9 @@ def repeat(id_or_ap_id, user, params \\ %{}) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unrepeat(id_or_ap_id, user) do
|
def unrepeat(id, user) do
|
||||||
with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do
|
with {_, %Activity{data: %{"type" => "Create"}} = activity} <-
|
||||||
|
{:find_activity, Activity.get_by_id(id)} do
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
ActivityPub.unannounce(user, object)
|
ActivityPub.unannounce(user, object)
|
||||||
else
|
else
|
||||||
|
@ -160,8 +162,9 @@ def favorite_helper(user, id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unfavorite(id_or_ap_id, user) do
|
def unfavorite(id, user) do
|
||||||
with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do
|
with {_, %Activity{data: %{"type" => "Create"}} = activity} <-
|
||||||
|
{:find_activity, Activity.get_by_id(id)} do
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
ActivityPub.unlike(user, object)
|
ActivityPub.unlike(user, object)
|
||||||
else
|
else
|
||||||
|
@ -322,12 +325,12 @@ def post(user, %{"status" => _} = data) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
|
def pin(id, %{ap_id: user_ap_id} = user) do
|
||||||
with %Activity{
|
with %Activity{
|
||||||
actor: ^user_ap_id,
|
actor: ^user_ap_id,
|
||||||
data: %{"type" => "Create"},
|
data: %{"type" => "Create"},
|
||||||
object: %Object{data: %{"type" => object_type}}
|
object: %Object{data: %{"type" => object_type}}
|
||||||
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
} = activity <- Activity.get_by_id_with_object(id),
|
||||||
true <- object_type in ["Note", "Article", "Question"],
|
true <- object_type in ["Note", "Article", "Question"],
|
||||||
true <- Visibility.is_public?(activity),
|
true <- Visibility.is_public?(activity),
|
||||||
{:ok, _user} <- User.add_pinnned_activity(user, activity) do
|
{:ok, _user} <- User.add_pinnned_activity(user, activity) do
|
||||||
|
@ -338,8 +341,8 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unpin(id_or_ap_id, user) do
|
def unpin(id, user) do
|
||||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
|
||||||
{:ok, _user} <- User.remove_pinnned_activity(user, activity) do
|
{:ok, _user} <- User.remove_pinnned_activity(user, activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,24 +22,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
require Logger
|
require Logger
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
# This is a hack for twidere.
|
|
||||||
def get_by_id_or_ap_id(id) do
|
|
||||||
activity =
|
|
||||||
with true <- FlakeId.flake_id?(id),
|
|
||||||
%Activity{} = activity <- Activity.get_by_id_with_object(id) do
|
|
||||||
activity
|
|
||||||
else
|
|
||||||
_ -> Activity.get_create_by_object_ap_id_with_object(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
activity &&
|
|
||||||
if activity.data["type"] == "Create" do
|
|
||||||
activity
|
|
||||||
else
|
|
||||||
Activity.get_create_by_object_ap_id_with_object(activity.data["object"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def attachments_from_ids(%{"media_ids" => ids, "descriptions" => desc} = _) do
|
def attachments_from_ids(%{"media_ids" => ids, "descriptions" => desc} = _) do
|
||||||
attachments_from_ids_descs(ids, desc)
|
attachments_from_ids_descs(ids, desc)
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,19 +72,24 @@ def perform(:incoming_ap_doc, params) do
|
||||||
# actor shouldn't be acting on objects outside their own AP server.
|
# actor shouldn't be acting on objects outside their own AP server.
|
||||||
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
|
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
|
||||||
nil <- Activity.normalize(params["id"]),
|
nil <- Activity.normalize(params["id"]),
|
||||||
:ok <- Containment.contain_origin_from_id(params["actor"], params),
|
{_, :ok} <-
|
||||||
|
{:correct_origin?, Containment.contain_origin_from_id(params["actor"], params)},
|
||||||
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
|
{:correct_origin?, _} ->
|
||||||
|
Logger.debug("Origin containment failure for #{params["id"]}")
|
||||||
|
{:error, :origin_containment_failed}
|
||||||
|
|
||||||
%Activity{} ->
|
%Activity{} ->
|
||||||
Logger.debug("Already had #{params["id"]}")
|
Logger.debug("Already had #{params["id"]}")
|
||||||
:error
|
{:error, :already_present}
|
||||||
|
|
||||||
_e ->
|
e ->
|
||||||
# Just drop those for now
|
# Just drop those for now
|
||||||
Logger.debug("Unhandled activity")
|
Logger.debug("Unhandled activity")
|
||||||
Logger.debug(Jason.encode!(params, pretty: true))
|
Logger.debug(Jason.encode!(params, pretty: true))
|
||||||
:error
|
{:error, e}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -293,7 +293,7 @@ def lists(%{assigns: %{user: user, account: account}} = conn, _params) do
|
||||||
|
|
||||||
@doc "POST /api/v1/accounts/:id/follow"
|
@doc "POST /api/v1/accounts/:id/follow"
|
||||||
def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
||||||
{:error, :not_found}
|
{:error, "Can not follow yourself"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
||||||
|
@ -306,7 +306,7 @@ def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
||||||
|
|
||||||
@doc "POST /api/v1/accounts/:id/unfollow"
|
@doc "POST /api/v1/accounts/:id/unfollow"
|
||||||
def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
||||||
{:error, :not_found}
|
{:error, "Can not unfollow yourself"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
||||||
|
@ -356,14 +356,15 @@ def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "POST /api/v1/follows"
|
@doc "POST /api/v1/follows"
|
||||||
def follows(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
|
def follows(conn, %{"uri" => uri}) do
|
||||||
with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)},
|
case User.get_cached_by_nickname(uri) do
|
||||||
{_, true} <- {:followed, follower.id != followed.id},
|
%User{} = user ->
|
||||||
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
|
conn
|
||||||
render(conn, "show.json", user: followed, for: follower)
|
|> assign(:account, user)
|
||||||
else
|
|> follow(%{})
|
||||||
{:followed, _} -> {:error, :not_found}
|
|
||||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
nil ->
|
||||||
|
{:error, :not_found}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.CustomEmojiController do
|
defmodule Pleroma.Web.MastodonAPI.CustomEmojiController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
plug(OpenApiSpex.Plug.CastAndValidate)
|
||||||
|
|
||||||
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.CustomEmojiOperation
|
||||||
|
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
render(conn, "index.json", custom_emojis: Pleroma.Emoji.get_all())
|
render(conn, "index.json", custom_emojis: Pleroma.Emoji.get_all())
|
||||||
end
|
end
|
||||||
|
|
|
@ -127,7 +127,8 @@ def index(%{assigns: %{user: user}} = conn, %{"ids" => ids} = params) do
|
||||||
def create(
|
def create(
|
||||||
%{assigns: %{user: user}} = conn,
|
%{assigns: %{user: user}} = conn,
|
||||||
%{"status" => _, "scheduled_at" => scheduled_at} = params
|
%{"status" => _, "scheduled_at" => scheduled_at} = params
|
||||||
) do
|
)
|
||||||
|
when not is_nil(scheduled_at) do
|
||||||
params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"])
|
params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"])
|
||||||
|
|
||||||
with {:far_enough, true} <- {:far_enough, ScheduledActivity.far_enough?(scheduled_at)},
|
with {:far_enough, true} <- {:far_enough, ScheduledActivity.far_enough?(scheduled_at)},
|
||||||
|
|
|
@ -19,6 +19,7 @@ def render("show.json", %{object: object, multiple: multiple, options: options}
|
||||||
expired: expired,
|
expired: expired,
|
||||||
multiple: multiple,
|
multiple: multiple,
|
||||||
votes_count: votes_count,
|
votes_count: votes_count,
|
||||||
|
voters_count: (multiple || nil) && voters_count(object),
|
||||||
options: options,
|
options: options,
|
||||||
voted: voted?(params),
|
voted: voted?(params),
|
||||||
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
|
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
|
||||||
|
@ -62,6 +63,12 @@ defp options_and_votes_count(options) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do
|
||||||
|
length(voters)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp voters_count(_), do: 0
|
||||||
|
|
||||||
defp voted?(%{object: object} = opts) do
|
defp voted?(%{object: object} = opts) do
|
||||||
if opts[:for] do
|
if opts[:for] do
|
||||||
existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object)
|
existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object)
|
||||||
|
|
|
@ -55,11 +55,12 @@ def perform(
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|> push_message(build_sub(subscription), gcm_api_key, subscription)
|
|> push_message(build_sub(subscription), gcm_api_key, subscription)
|
||||||
end
|
end
|
||||||
|
|> (&{:ok, &1}).()
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(_) do
|
def perform(_) do
|
||||||
Logger.warn("Unknown notification type")
|
Logger.warn("Unknown notification type")
|
||||||
:error
|
{:error, :unknown_type}
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Push message to web"
|
@doc "Push message to web"
|
||||||
|
|
|
@ -16,79 +16,60 @@ defmodule Pleroma.Web.Router do
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
plug(Pleroma.Plugs.UserEnabledPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :api do
|
pipeline :authenticate do
|
||||||
plug(:accepts, ["json"])
|
|
||||||
plug(:fetch_session)
|
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
plug(Pleroma.Plugs.OAuthPlug)
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
plug(Pleroma.Plugs.UserFetcherPlug)
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
||||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
plug(Pleroma.Plugs.AuthenticationPlug)
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline :after_auth do
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
plug(Pleroma.Plugs.UserEnabledPlug)
|
||||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
||||||
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
||||||
plug(Pleroma.Plugs.IdempotencyPlug)
|
end
|
||||||
|
|
||||||
|
pipeline :base_api do
|
||||||
|
plug(:accepts, ["json"])
|
||||||
|
plug(:fetch_session)
|
||||||
|
plug(:authenticate)
|
||||||
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
|
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pipeline :api do
|
||||||
|
plug(:base_api)
|
||||||
|
plug(:after_auth)
|
||||||
|
plug(Pleroma.Plugs.IdempotencyPlug)
|
||||||
|
end
|
||||||
|
|
||||||
pipeline :authenticated_api do
|
pipeline :authenticated_api do
|
||||||
plug(:accepts, ["json"])
|
plug(:base_api)
|
||||||
plug(:fetch_session)
|
|
||||||
plug(Pleroma.Plugs.AuthExpectedPlug)
|
plug(Pleroma.Plugs.AuthExpectedPlug)
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
plug(:after_auth)
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
|
||||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
|
||||||
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
||||||
plug(Pleroma.Plugs.IdempotencyPlug)
|
plug(Pleroma.Plugs.IdempotencyPlug)
|
||||||
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :admin_api do
|
pipeline :admin_api do
|
||||||
plug(:accepts, ["json"])
|
plug(:base_api)
|
||||||
plug(:fetch_session)
|
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AdminSecretAuthenticationPlug)
|
plug(Pleroma.Plugs.AdminSecretAuthenticationPlug)
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
plug(:after_auth)
|
||||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
|
||||||
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
||||||
plug(Pleroma.Plugs.UserIsAdminPlug)
|
plug(Pleroma.Plugs.UserIsAdminPlug)
|
||||||
plug(Pleroma.Plugs.IdempotencyPlug)
|
plug(Pleroma.Plugs.IdempotencyPlug)
|
||||||
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :mastodon_html do
|
pipeline :mastodon_html do
|
||||||
plug(:accepts, ["html"])
|
plug(:browser)
|
||||||
plug(:fetch_session)
|
plug(:authenticate)
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
plug(:after_auth)
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
|
||||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
|
||||||
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :pleroma_html do
|
pipeline :pleroma_html do
|
||||||
plug(:accepts, ["html"])
|
plug(:browser)
|
||||||
plug(:fetch_session)
|
plug(:authenticate)
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -515,7 +496,7 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/api" do
|
scope "/api" do
|
||||||
pipe_through(:api)
|
pipe_through(:base_api)
|
||||||
|
|
||||||
get("/openapi", OpenApiSpex.Plug.RenderSpec, [])
|
get("/openapi", OpenApiSpex.Plug.RenderSpec, [])
|
||||||
end
|
end
|
||||||
|
@ -529,10 +510,6 @@ defmodule Pleroma.Web.Router do
|
||||||
post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
|
post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :ap_service_actor do
|
|
||||||
plug(:accepts, ["activity+json", "json"])
|
|
||||||
end
|
|
||||||
|
|
||||||
pipeline :ostatus do
|
pipeline :ostatus do
|
||||||
plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
|
plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
|
||||||
plug(Pleroma.Plugs.StaticFEPlug)
|
plug(Pleroma.Plugs.StaticFEPlug)
|
||||||
|
@ -543,8 +520,7 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web do
|
scope "/", Pleroma.Web do
|
||||||
pipe_through(:ostatus)
|
pipe_through([:ostatus, :http_signature])
|
||||||
pipe_through(:http_signature)
|
|
||||||
|
|
||||||
get("/objects/:uuid", OStatus.OStatusController, :object)
|
get("/objects/:uuid", OStatus.OStatusController, :object)
|
||||||
get("/activities/:uuid", OStatus.OStatusController, :activity)
|
get("/activities/:uuid", OStatus.OStatusController, :activity)
|
||||||
|
@ -562,13 +538,6 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)
|
get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Server to Server (S2S) AP interactions
|
|
||||||
pipeline :activitypub do
|
|
||||||
plug(:accepts, ["activity+json", "json"])
|
|
||||||
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
|
||||||
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope "/", Pleroma.Web.ActivityPub do
|
scope "/", Pleroma.Web.ActivityPub do
|
||||||
# XXX: not really ostatus
|
# XXX: not really ostatus
|
||||||
pipe_through(:ostatus)
|
pipe_through(:ostatus)
|
||||||
|
@ -576,19 +545,22 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/users/:nickname/outbox", ActivityPubController, :outbox)
|
get("/users/:nickname/outbox", ActivityPubController, :outbox)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pipeline :ap_service_actor do
|
||||||
|
plug(:accepts, ["activity+json", "json"])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Server to Server (S2S) AP interactions
|
||||||
|
pipeline :activitypub do
|
||||||
|
plug(:ap_service_actor)
|
||||||
|
plug(:http_signature)
|
||||||
|
end
|
||||||
|
|
||||||
# Client to Server (C2S) AP interactions
|
# Client to Server (C2S) AP interactions
|
||||||
pipeline :activitypub_client do
|
pipeline :activitypub_client do
|
||||||
plug(:accepts, ["activity+json", "json"])
|
plug(:ap_service_actor)
|
||||||
plug(:fetch_session)
|
plug(:fetch_session)
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
plug(:authenticate)
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
plug(:after_auth)
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
|
||||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
|
||||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
|
||||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
|
||||||
plug(Pleroma.Plugs.EnsureUserKeyPlug)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web.ActivityPub do
|
scope "/", Pleroma.Web.ActivityPub do
|
||||||
|
@ -660,12 +632,7 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/web/*path", MastoFEController, :index)
|
get("/web/*path", MastoFEController, :index)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :remote_media do
|
|
||||||
end
|
|
||||||
|
|
||||||
scope "/proxy/", Pleroma.Web.MediaProxy do
|
scope "/proxy/", Pleroma.Web.MediaProxy do
|
||||||
pipe_through(:remote_media)
|
|
||||||
|
|
||||||
get("/:sig/:url", MediaProxyController, :remote)
|
get("/:sig/:url", MediaProxyController, :remote)
|
||||||
get("/:sig/:url/:filename", MediaProxyController, :remote)
|
get("/:sig/:url/:filename", MediaProxyController, :remote)
|
||||||
end
|
end
|
||||||
|
|
|
@ -158,24 +158,6 @@ defp should_send?(%User{} = user, %Notification{activity: activity}) do
|
||||||
should_send?(user, activity)
|
should_send?(user, activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do
|
|
||||||
Enum.each(topics[topic] || [], fn %StreamerSocket{
|
|
||||||
transport_pid: transport_pid,
|
|
||||||
user: socket_user
|
|
||||||
} ->
|
|
||||||
# Get the current user so we have up-to-date blocks etc.
|
|
||||||
if socket_user do
|
|
||||||
user = User.get_cached_by_ap_id(socket_user.ap_id)
|
|
||||||
|
|
||||||
if should_send?(user, item) do
|
|
||||||
send(transport_pid, {:text, StreamerView.render("update.json", item, user)})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
send(transport_pid, {:text, StreamerView.render("update.json", item)})
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
def push_to_socket(topics, topic, %Participation{} = participation) do
|
def push_to_socket(topics, topic, %Participation{} = participation) do
|
||||||
Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} ->
|
Enum.each(topics[topic] || [], fn %StreamerSocket{transport_pid: transport_pid} ->
|
||||||
send(transport_pid, {:text, StreamerView.render("conversation.json", participation)})
|
send(transport_pid, {:text, StreamerView.render("conversation.json", participation)})
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<%= case @mediaType do %>
|
<%= case @mediaType do %>
|
||||||
<% "audio" -> %>
|
<% "audio" -> %>
|
||||||
<audio src="<%= @url %>" controls="controls"></audio>
|
<audio class="u-audio" src="<%= @url %>" controls="controls"></audio>
|
||||||
<% "video" -> %>
|
<% "video" -> %>
|
||||||
<video src="<%= @url %>" controls="controls"></video>
|
<video class="u-video" src="<%= @url %>" controls="controls"></video>
|
||||||
<% _ -> %>
|
<% _ -> %>
|
||||||
<img src="<%= @url %>" alt="<%= @name %>" title="<%= @name %>">
|
<img class="u-photo" src="<%= @url %>" alt="<%= @name %>" title="<%= @name %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
<div class="activity" <%= if @selected do %> id="selected" <% end %>>
|
<div class="activity h-entry" <%= if @selected do %> id="selected" <% end %>>
|
||||||
<p class="pull-right">
|
<p class="pull-right">
|
||||||
<%= link format_date(@published), to: @link, class: "activity-link" %>
|
<a class="activity-link u-url u-uid" href="<%= @link %>">
|
||||||
|
<time class="dt-published" datetime="<%= @published %>">
|
||||||
|
<%= format_date(@published) %>
|
||||||
|
</time>
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<%= render("_user_card.html", %{user: @user}) %>
|
<%= render("_user_card.html", %{user: @user}) %>
|
||||||
<div class="activity-content">
|
<div class="activity-content">
|
||||||
<%= if @title != "" do %>
|
<%= if @title != "" do %>
|
||||||
<details <%= if open_content?() do %>open<% end %>>
|
<details <%= if open_content?() do %>open<% end %>>
|
||||||
<summary><%= raw @title %></summary>
|
<summary class="p-name"><%= raw @title %></summary>
|
||||||
<div class="e-content"><%= raw @content %></div>
|
<div class="e-content"><%= raw @content %></div>
|
||||||
</details>
|
</details>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="p-author h-card">
|
<div class="p-author h-card">
|
||||||
<a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>">
|
<a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt="">
|
<img class="u-photo" src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt="">
|
||||||
</div>
|
</div>
|
||||||
<span class="display-name">
|
<span class="display-name">
|
||||||
<bdi><%= raw Formatter.emojify(@user.name, @user.emoji) %></bdi>
|
<bdi class="p-name"><%= raw Formatter.emojify(@user.name, @user.emoji) %></bdi>
|
||||||
<span class="nickname"><%= @user.nickname %></span>
|
<span class="nickname"><%= @user.nickname %></span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -199,27 +199,27 @@ def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
|
def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
|
||||||
with lines <- String.split(list, "\n"),
|
followed_identifiers =
|
||||||
followed_identifiers <-
|
list
|
||||||
Enum.map(lines, fn line ->
|
|> String.split("\n")
|
||||||
String.split(line, ",") |> List.first()
|
|> Enum.map(&(&1 |> String.split(",") |> List.first()))
|
||||||
end)
|
|> List.delete("Account address")
|
||||||
|> List.delete("Account address") do
|
|> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
|
||||||
|
|> Enum.reject(&(&1 == ""))
|
||||||
|
|
||||||
User.follow_import(follower, followed_identifiers)
|
User.follow_import(follower, followed_identifiers)
|
||||||
json(conn, "job started")
|
json(conn, "job started")
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
|
def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
|
||||||
blocks_import(conn, %{"list" => File.read!(listfile.path)})
|
blocks_import(conn, %{"list" => File.read!(listfile.path)})
|
||||||
end
|
end
|
||||||
|
|
||||||
def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
|
def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
|
||||||
with blocked_identifiers <- String.split(list) do
|
blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@"))
|
||||||
User.blocks_import(blocker, blocked_identifiers)
|
User.blocks_import(blocker, blocked_identifiers)
|
||||||
json(conn, "job started")
|
json(conn, "job started")
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def change_password(%{assigns: %{user: user}} = conn, params) do
|
def change_password(%{assigns: %{user: user}} = conn, params) do
|
||||||
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||||
|
|
|
@ -35,7 +35,7 @@ def perform(
|
||||||
_job
|
_job
|
||||||
) do
|
) do
|
||||||
blocker = User.get_cached_by_id(blocker_id)
|
blocker = User.get_cached_by_id(blocker_id)
|
||||||
User.perform(:blocks_import, blocker, blocked_identifiers)
|
{:ok, User.perform(:blocks_import, blocker, blocked_identifiers)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(
|
def perform(
|
||||||
|
@ -47,7 +47,7 @@ def perform(
|
||||||
_job
|
_job
|
||||||
) do
|
) do
|
||||||
follower = User.get_cached_by_id(follower_id)
|
follower = User.get_cached_by_id(follower_id)
|
||||||
User.perform(:follow_import, follower, followed_identifiers)
|
{:ok, User.perform(:follow_import, follower, followed_identifiers)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do
|
def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do
|
||||||
|
|
|
@ -16,6 +16,7 @@ test "transfer config values from db to env" do
|
||||||
refute Application.get_env(:pleroma, :test_key)
|
refute Application.get_env(:pleroma, :test_key)
|
||||||
refute Application.get_env(:idna, :test_key)
|
refute Application.get_env(:idna, :test_key)
|
||||||
refute Application.get_env(:quack, :test_key)
|
refute Application.get_env(:quack, :test_key)
|
||||||
|
refute Application.get_env(:postgrex, :test_key)
|
||||||
initial = Application.get_env(:logger, :level)
|
initial = Application.get_env(:logger, :level)
|
||||||
|
|
||||||
ConfigDB.create(%{
|
ConfigDB.create(%{
|
||||||
|
@ -36,6 +37,12 @@ test "transfer config values from db to env" do
|
||||||
value: [:test_value1, :test_value2]
|
value: [:test_value1, :test_value2]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ConfigDB.create(%{
|
||||||
|
group: ":postgrex",
|
||||||
|
key: ":test_key",
|
||||||
|
value: :value
|
||||||
|
})
|
||||||
|
|
||||||
ConfigDB.create(%{group: ":logger", key: ":level", value: :debug})
|
ConfigDB.create(%{group: ":logger", key: ":level", value: :debug})
|
||||||
|
|
||||||
TransferTask.start_link([])
|
TransferTask.start_link([])
|
||||||
|
@ -44,11 +51,13 @@ test "transfer config values from db to env" do
|
||||||
assert Application.get_env(:idna, :test_key) == [live: 15, com: 35]
|
assert Application.get_env(:idna, :test_key) == [live: 15, com: 35]
|
||||||
assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2]
|
assert Application.get_env(:quack, :test_key) == [:test_value1, :test_value2]
|
||||||
assert Application.get_env(:logger, :level) == :debug
|
assert Application.get_env(:logger, :level) == :debug
|
||||||
|
assert Application.get_env(:postgrex, :test_key) == :value
|
||||||
|
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
Application.delete_env(:pleroma, :test_key)
|
Application.delete_env(:pleroma, :test_key)
|
||||||
Application.delete_env(:idna, :test_key)
|
Application.delete_env(:idna, :test_key)
|
||||||
Application.delete_env(:quack, :test_key)
|
Application.delete_env(:quack, :test_key)
|
||||||
|
Application.delete_env(:postgrex, :test_key)
|
||||||
Application.put_env(:logger, :level, initial)
|
Application.put_env(:logger, :level, initial)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,3 +7,5 @@
|
||||||
config :quack, level: :info
|
config :quack, level: :info
|
||||||
|
|
||||||
config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox
|
config :pleroma, Pleroma.Repo, pool: Ecto.Adapters.SQL.Sandbox
|
||||||
|
|
||||||
|
config :postgrex, :json_library, Poison
|
||||||
|
|
|
@ -2,11 +2,21 @@
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.StateTest do
|
defmodule Pleroma.StatsTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
describe "user count" do
|
||||||
|
test "it ignores internal users" do
|
||||||
|
_user = insert(:user, local: true)
|
||||||
|
_internal = insert(:user, local: true, nickname: nil)
|
||||||
|
_internal = Pleroma.Web.ActivityPub.Relay.get_actor()
|
||||||
|
|
||||||
|
assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "status visibility count" do
|
describe "status visibility count" do
|
||||||
test "on new status" do
|
test "on new status" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
|
@ -38,7 +38,7 @@ test "error if file with custom settings doesn't exist" do
|
||||||
on_exit(fn -> Application.put_env(:quack, :level, initial) end)
|
on_exit(fn -> Application.put_env(:quack, :level, initial) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "settings are migrated to db" do
|
test "filtered settings are migrated to db" do
|
||||||
assert Repo.all(ConfigDB) == []
|
assert Repo.all(ConfigDB) == []
|
||||||
|
|
||||||
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
|
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
|
||||||
|
@ -47,6 +47,7 @@ test "settings are migrated to db" do
|
||||||
config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
|
config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
|
||||||
config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
|
config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
|
||||||
refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
|
refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
|
||||||
|
refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"})
|
||||||
|
|
||||||
assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]]
|
assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]]
|
||||||
assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]]
|
assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]]
|
||||||
|
|
|
@ -756,8 +756,8 @@ test "it imports user followings from list" do
|
||||||
]
|
]
|
||||||
|
|
||||||
{:ok, job} = User.follow_import(user1, identifiers)
|
{:ok, job} = User.follow_import(user1, identifiers)
|
||||||
result = ObanHelpers.perform(job)
|
|
||||||
|
|
||||||
|
assert {:ok, result} = ObanHelpers.perform(job)
|
||||||
assert is_list(result)
|
assert is_list(result)
|
||||||
assert result == [user2, user3]
|
assert result == [user2, user3]
|
||||||
end
|
end
|
||||||
|
@ -979,14 +979,26 @@ test "it imports user blocks from list" do
|
||||||
]
|
]
|
||||||
|
|
||||||
{:ok, job} = User.blocks_import(user1, identifiers)
|
{:ok, job} = User.blocks_import(user1, identifiers)
|
||||||
result = ObanHelpers.perform(job)
|
|
||||||
|
|
||||||
|
assert {:ok, result} = ObanHelpers.perform(job)
|
||||||
assert is_list(result)
|
assert is_list(result)
|
||||||
assert result == [user2, user3]
|
assert result == [user2, user3]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "get_recipients_from_activity" do
|
describe "get_recipients_from_activity" do
|
||||||
|
test "works for announces" do
|
||||||
|
actor = insert(:user)
|
||||||
|
user = insert(:user, local: true)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(actor, %{"status" => "hello"})
|
||||||
|
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
|
||||||
|
|
||||||
|
recipients = User.get_recipients_from_activity(announce)
|
||||||
|
|
||||||
|
assert user in recipients
|
||||||
|
end
|
||||||
|
|
||||||
test "get recipients" do
|
test "get recipients" do
|
||||||
actor = insert(:user)
|
actor = insert(:user)
|
||||||
user = insert(:user, local: true)
|
user = insert(:user, local: true)
|
||||||
|
|
|
@ -994,72 +994,6 @@ test "reverts emoji unreact on error" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "like an object" do
|
|
||||||
test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
|
|
||||||
Config.put([:instance, :federating], true)
|
|
||||||
note_activity = insert(:note_activity)
|
|
||||||
assert object_activity = Object.normalize(note_activity)
|
|
||||||
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
|
|
||||||
assert called(Federator.publish(like_activity))
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns exist activity if object already liked" do
|
|
||||||
note_activity = insert(:note_activity)
|
|
||||||
assert object_activity = Object.normalize(note_activity)
|
|
||||||
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
|
|
||||||
|
|
||||||
{:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
|
|
||||||
assert like_activity == like_activity_exist
|
|
||||||
end
|
|
||||||
|
|
||||||
test "reverts like activity on error" do
|
|
||||||
note_activity = insert(:note_activity)
|
|
||||||
object = Object.normalize(note_activity)
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
|
|
||||||
assert {:error, :reverted} = ActivityPub.like(user, object)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert Repo.aggregate(Activity, :count, :id) == 1
|
|
||||||
assert Repo.get(Object, object.id) == object
|
|
||||||
end
|
|
||||||
|
|
||||||
test "adds a like activity to the db" do
|
|
||||||
note_activity = insert(:note_activity)
|
|
||||||
assert object = Object.normalize(note_activity)
|
|
||||||
|
|
||||||
user = insert(:user)
|
|
||||||
user_two = insert(:user)
|
|
||||||
|
|
||||||
{:ok, like_activity, object} = ActivityPub.like(user, object)
|
|
||||||
|
|
||||||
assert like_activity.data["actor"] == user.ap_id
|
|
||||||
assert like_activity.data["type"] == "Like"
|
|
||||||
assert like_activity.data["object"] == object.data["id"]
|
|
||||||
assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
|
|
||||||
assert like_activity.data["context"] == object.data["context"]
|
|
||||||
assert object.data["like_count"] == 1
|
|
||||||
assert object.data["likes"] == [user.ap_id]
|
|
||||||
|
|
||||||
# Just return the original activity if the user already liked it.
|
|
||||||
{:ok, same_like_activity, object} = ActivityPub.like(user, object)
|
|
||||||
|
|
||||||
assert like_activity == same_like_activity
|
|
||||||
assert object.data["likes"] == [user.ap_id]
|
|
||||||
assert object.data["like_count"] == 1
|
|
||||||
|
|
||||||
{:ok, _like_activity, object} = ActivityPub.like(user_two, object)
|
|
||||||
assert object.data["like_count"] == 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "unliking" do
|
describe "unliking" do
|
||||||
test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
|
test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
|
||||||
Config.put([:instance, :federating], true)
|
Config.put([:instance, :federating], true)
|
||||||
|
@ -1071,7 +1005,8 @@ test "adds a like activity to the db" do
|
||||||
{:ok, object} = ActivityPub.unlike(user, object)
|
{:ok, object} = ActivityPub.unlike(user, object)
|
||||||
refute called(Federator.publish())
|
refute called(Federator.publish())
|
||||||
|
|
||||||
{:ok, _like_activity, object} = ActivityPub.like(user, object)
|
{:ok, _like_activity} = CommonAPI.favorite(user, note_activity.id)
|
||||||
|
object = Object.get_by_id(object.id)
|
||||||
assert object.data["like_count"] == 1
|
assert object.data["like_count"] == 1
|
||||||
|
|
||||||
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
|
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
|
||||||
|
@ -1082,10 +1017,10 @@ test "adds a like activity to the db" do
|
||||||
|
|
||||||
test "reverts unliking on error" do
|
test "reverts unliking on error" do
|
||||||
note_activity = insert(:note_activity)
|
note_activity = insert(:note_activity)
|
||||||
object = Object.normalize(note_activity)
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
{:ok, like_activity, object} = ActivityPub.like(user, object)
|
{:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
|
||||||
|
object = Object.normalize(note_activity)
|
||||||
assert object.data["like_count"] == 1
|
assert object.data["like_count"] == 1
|
||||||
|
|
||||||
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
|
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
|
||||||
|
@ -1106,7 +1041,9 @@ test "unliking a previously liked object" do
|
||||||
{:ok, object} = ActivityPub.unlike(user, object)
|
{:ok, object} = ActivityPub.unlike(user, object)
|
||||||
assert object.data["like_count"] == 0
|
assert object.data["like_count"] == 0
|
||||||
|
|
||||||
{:ok, like_activity, object} = ActivityPub.like(user, object)
|
{:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
|
||||||
|
|
||||||
|
object = Object.get_by_id(object.id)
|
||||||
assert object.data["like_count"] == 1
|
assert object.data["like_count"] == 1
|
||||||
|
|
||||||
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
|
{:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
|
||||||
|
|
|
@ -17,7 +17,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
||||||
reject: [],
|
reject: [],
|
||||||
accept: [],
|
accept: [],
|
||||||
avatar_removal: [],
|
avatar_removal: [],
|
||||||
banner_removal: []
|
banner_removal: [],
|
||||||
|
reject_deletes: []
|
||||||
)
|
)
|
||||||
|
|
||||||
describe "when :media_removal" do
|
describe "when :media_removal" do
|
||||||
|
@ -382,6 +383,66 @@ test "match with wildcard domain" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "when :reject_deletes is empty" do
|
||||||
|
setup do: Config.put([:mrf_simple, :reject_deletes], [])
|
||||||
|
|
||||||
|
test "it accepts deletions even from rejected servers" do
|
||||||
|
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||||
|
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it accepts deletions even from non-whitelisted servers" do
|
||||||
|
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||||
|
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
|
||||||
|
setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"])
|
||||||
|
|
||||||
|
test "it accepts deletions even from rejected servers" do
|
||||||
|
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||||
|
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it accepts deletions even from non-whitelisted servers" do
|
||||||
|
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||||
|
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when :reject_deletes has a matching host" do
|
||||||
|
setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"])
|
||||||
|
|
||||||
|
test "it rejects the deletion" do
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:reject, nil}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when :reject_deletes match with wildcard domain" do
|
||||||
|
setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"])
|
||||||
|
|
||||||
|
test "it rejects the deletion" do
|
||||||
|
deletion_message = build_remote_deletion_message()
|
||||||
|
|
||||||
|
assert SimplePolicy.filter(deletion_message) == {:reject, nil}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp build_local_message do
|
defp build_local_message do
|
||||||
%{
|
%{
|
||||||
"actor" => "#{Pleroma.Web.base_url()}/users/alice",
|
"actor" => "#{Pleroma.Web.base_url()}/users/alice",
|
||||||
|
@ -408,4 +469,11 @@ defp build_remote_user do
|
||||||
"type" => "Person"
|
"type" => "Person"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp build_remote_deletion_message do
|
||||||
|
%{
|
||||||
|
"type" => "Delete",
|
||||||
|
"actor" => "https://remote.instance/users/bob"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -224,8 +224,7 @@ test "fetches only Create activities" do
|
||||||
|
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
{:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
|
{:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
|
||||||
vote_object = Object.normalize(vote)
|
{:ok, _activity} = CommonAPI.favorite(user, activity.id)
|
||||||
{:ok, _activity, _object} = ActivityPub.like(user, vote_object)
|
|
||||||
[fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
|
[fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
|
||||||
assert fetched_vote.id == vote.id
|
assert fetched_vote.id == vote.id
|
||||||
end
|
end
|
||||||
|
@ -346,7 +345,7 @@ test "fetches existing like" do
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
refute Utils.get_existing_like(user.ap_id, object)
|
refute Utils.get_existing_like(user.ap_id, object)
|
||||||
{:ok, like_activity, _object} = ActivityPub.like(user, object)
|
{:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
|
||||||
|
|
||||||
assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
|
assert ^like_activity = Utils.get_existing_like(user.ap_id, object)
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,33 @@ defmodule Pleroma.Web.CommonAPITest do
|
||||||
setup do: clear_config([:instance, :limit])
|
setup do: clear_config([:instance, :limit])
|
||||||
setup do: clear_config([:instance, :max_pinned_statuses])
|
setup do: clear_config([:instance, :max_pinned_statuses])
|
||||||
|
|
||||||
|
test "favoriting race condition" do
|
||||||
|
user = insert(:user)
|
||||||
|
users_serial = insert_list(10, :user)
|
||||||
|
users = insert_list(10, :user)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "."})
|
||||||
|
|
||||||
|
users_serial
|
||||||
|
|> Enum.map(fn user ->
|
||||||
|
CommonAPI.favorite(user, activity.id)
|
||||||
|
end)
|
||||||
|
|
||||||
|
object = Object.get_by_ap_id(activity.data["object"])
|
||||||
|
assert object.data["like_count"] == 10
|
||||||
|
|
||||||
|
users
|
||||||
|
|> Enum.map(fn user ->
|
||||||
|
Task.async(fn ->
|
||||||
|
CommonAPI.favorite(user, activity.id)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|> Enum.map(&Task.await/1)
|
||||||
|
|
||||||
|
object = Object.get_by_ap_id(activity.data["object"])
|
||||||
|
assert object.data["like_count"] == 20
|
||||||
|
end
|
||||||
|
|
||||||
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
|
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
{:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
|
{:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
|
||||||
|
@ -256,6 +283,16 @@ test "repeating a status" do
|
||||||
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
|
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "can't repeat a repeat" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
||||||
|
|
||||||
|
{:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user)
|
||||||
|
|
||||||
|
refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user))
|
||||||
|
end
|
||||||
|
|
||||||
test "repeating a status privately" do
|
test "repeating a status privately" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
@ -285,8 +322,8 @@ test "retweeting a status twice returns the status" do
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
||||||
{:ok, %Activity{} = activity, object} = CommonAPI.repeat(activity.id, user)
|
{:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user)
|
||||||
{:ok, ^activity, ^object} = CommonAPI.repeat(activity.id, user)
|
{:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "favoriting a status twice returns ok, but without the like activity" do
|
test "favoriting a status twice returns ok, but without the like activity" do
|
||||||
|
@ -360,7 +397,9 @@ test "unpin status", %{user: user, activity: activity} do
|
||||||
|
|
||||||
user = refresh_record(user)
|
user = refresh_record(user)
|
||||||
|
|
||||||
assert {:ok, ^activity} = CommonAPI.unpin(activity.id, user)
|
id = activity.id
|
||||||
|
|
||||||
|
assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
|
||||||
|
|
||||||
user = refresh_record(user)
|
user = refresh_record(user)
|
||||||
|
|
||||||
|
|
|
@ -335,26 +335,6 @@ test "for direct posts, a reply" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "get_by_id_or_ap_id/1" do
|
|
||||||
test "get activity by id" do
|
|
||||||
activity = insert(:note_activity)
|
|
||||||
%Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.id)
|
|
||||||
assert note.id == activity.id
|
|
||||||
end
|
|
||||||
|
|
||||||
test "get activity by ap_id" do
|
|
||||||
activity = insert(:note_activity)
|
|
||||||
%Pleroma.Activity{} = note = Utils.get_by_id_or_ap_id(activity.data["object"])
|
|
||||||
assert note.id == activity.id
|
|
||||||
end
|
|
||||||
|
|
||||||
test "get activity by object when type isn't `Create` " do
|
|
||||||
activity = insert(:like_activity)
|
|
||||||
%Pleroma.Activity{} = like = Utils.get_by_id_or_ap_id(activity.id)
|
|
||||||
assert like.data["object"] == activity.data["object"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "to_master_date/1" do
|
describe "to_master_date/1" do
|
||||||
test "removes microseconds from date (NaiveDateTime)" do
|
test "removes microseconds from date (NaiveDateTime)" do
|
||||||
assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z"
|
assert Utils.to_masto_date(~N[2015-01-23 23:50:07.123]) == "2015-01-23T23:50:07.000Z"
|
||||||
|
|
|
@ -130,6 +130,9 @@ test "successfully processes incoming AP docs with correct origin" do
|
||||||
|
|
||||||
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||||
assert {:ok, _activity} = ObanHelpers.perform(job)
|
assert {:ok, _activity} = ObanHelpers.perform(job)
|
||||||
|
|
||||||
|
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||||
|
assert {:error, :already_present} = ObanHelpers.perform(job)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rejects incoming AP docs with incorrect origin" do
|
test "rejects incoming AP docs with incorrect origin" do
|
||||||
|
@ -148,7 +151,7 @@ test "rejects incoming AP docs with incorrect origin" do
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||||
assert :error = ObanHelpers.perform(job)
|
assert {:error, :origin_containment_failed} = ObanHelpers.perform(job)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it does not crash if MRF rejects the post" do
|
test "it does not crash if MRF rejects the post" do
|
||||||
|
@ -164,7 +167,7 @@ test "it does not crash if MRF rejects the post" do
|
||||||
|> Poison.decode!()
|
|> Poison.decode!()
|
||||||
|
|
||||||
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||||
assert :error = ObanHelpers.perform(job)
|
assert {:error, _} = ObanHelpers.perform(job)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -681,17 +681,17 @@ test "following without reblogs" do
|
||||||
test "following / unfollowing errors", %{user: user, conn: conn} do
|
test "following / unfollowing errors", %{user: user, conn: conn} do
|
||||||
# self follow
|
# self follow
|
||||||
conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
|
conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
|
||||||
assert %{"error" => "Record not found"} = json_response(conn_res, 404)
|
assert %{"error" => "Can not follow yourself"} = json_response(conn_res, 400)
|
||||||
|
|
||||||
# self unfollow
|
# self unfollow
|
||||||
user = User.get_cached_by_id(user.id)
|
user = User.get_cached_by_id(user.id)
|
||||||
conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
|
conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
|
||||||
assert %{"error" => "Record not found"} = json_response(conn_res, 404)
|
assert %{"error" => "Can not unfollow yourself"} = json_response(conn_res, 400)
|
||||||
|
|
||||||
# self follow via uri
|
# self follow via uri
|
||||||
user = User.get_cached_by_id(user.id)
|
user = User.get_cached_by_id(user.id)
|
||||||
conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
|
conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
|
||||||
assert %{"error" => "Record not found"} = json_response(conn_res, 404)
|
assert %{"error" => "Can not follow yourself"} = json_response(conn_res, 400)
|
||||||
|
|
||||||
# follow non existing user
|
# follow non existing user
|
||||||
conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
|
conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
|
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
|
||||||
use Pleroma.Web.ConnCase, async: true
|
use Pleroma.Web.ConnCase, async: true
|
||||||
|
alias Pleroma.Web.ApiSpec
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
|
||||||
|
import OpenApiSpex.TestAssertions
|
||||||
|
|
||||||
test "with tags", %{conn: conn} do
|
test "with tags", %{conn: conn} do
|
||||||
[emoji | _body] =
|
assert resp =
|
||||||
conn
|
conn
|
||||||
|> get("/api/v1/custom_emojis")
|
|> get("/api/v1/custom_emojis")
|
||||||
|> json_response(200)
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert [emoji | _body] = resp
|
||||||
assert Map.has_key?(emoji, "shortcode")
|
assert Map.has_key?(emoji, "shortcode")
|
||||||
assert Map.has_key?(emoji, "static_url")
|
assert Map.has_key?(emoji, "static_url")
|
||||||
assert Map.has_key?(emoji, "tags")
|
assert Map.has_key?(emoji, "tags")
|
||||||
|
@ -18,5 +23,19 @@ test "with tags", %{conn: conn} do
|
||||||
assert Map.has_key?(emoji, "category")
|
assert Map.has_key?(emoji, "category")
|
||||||
assert Map.has_key?(emoji, "url")
|
assert Map.has_key?(emoji, "url")
|
||||||
assert Map.has_key?(emoji, "visible_in_picker")
|
assert Map.has_key?(emoji, "visible_in_picker")
|
||||||
|
assert_schema(resp, "CustomEmojisResponse", ApiSpec.spec())
|
||||||
|
assert_schema(emoji, "CustomEmoji", ApiSpec.spec())
|
||||||
|
end
|
||||||
|
|
||||||
|
test "CustomEmoji example matches schema" do
|
||||||
|
api_spec = ApiSpec.spec()
|
||||||
|
schema = CustomEmoji.schema()
|
||||||
|
assert_schema(schema.example, "CustomEmoji", api_spec)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "CustomEmojisResponse example matches schema" do
|
||||||
|
api_spec = ApiSpec.spec()
|
||||||
|
schema = CustomEmojisResponse.schema()
|
||||||
|
assert_schema(schema.example, "CustomEmojisResponse", api_spec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -302,6 +302,17 @@ test "creates a scheduled activity", %{conn: conn} do
|
||||||
assert [] == Repo.all(Activity)
|
assert [] == Repo.all(Activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "ignores nil values", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
post(conn, "/api/v1/statuses", %{
|
||||||
|
"status" => "not scheduled",
|
||||||
|
"scheduled_at" => nil
|
||||||
|
})
|
||||||
|
|
||||||
|
assert result = json_response(conn, 200)
|
||||||
|
assert Activity.get_by_id(result["id"])
|
||||||
|
end
|
||||||
|
|
||||||
test "creates a scheduled activity with a media attachment", %{user: user, conn: conn} do
|
test "creates a scheduled activity with a media attachment", %{user: user, conn: conn} do
|
||||||
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
|
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ test "renders a poll" do
|
||||||
%{title: "why are you even asking?", votes_count: 0}
|
%{title: "why are you even asking?", votes_count: 0}
|
||||||
],
|
],
|
||||||
voted: false,
|
voted: false,
|
||||||
votes_count: 0
|
votes_count: 0,
|
||||||
|
voters_count: nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PollView.render("show.json", %{object: object})
|
result = PollView.render("show.json", %{object: object})
|
||||||
|
@ -69,9 +70,20 @@ test "detects if it is multiple choice" do
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
voter = insert(:user)
|
||||||
|
|
||||||
object = Object.normalize(activity)
|
object = Object.normalize(activity)
|
||||||
|
|
||||||
assert %{multiple: true} = PollView.render("show.json", %{object: object})
|
{:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1])
|
||||||
|
|
||||||
|
assert match?(
|
||||||
|
%{
|
||||||
|
multiple: true,
|
||||||
|
voters_count: 1,
|
||||||
|
votes_count: 2
|
||||||
|
},
|
||||||
|
PollView.render("show.json", %{object: object})
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "detects emoji" do
|
test "detects emoji" do
|
||||||
|
|
|
@ -63,12 +63,12 @@ test "performs sending notifications" do
|
||||||
activity: activity
|
activity: activity
|
||||||
)
|
)
|
||||||
|
|
||||||
assert Impl.perform(notif) == [:ok, :ok]
|
assert Impl.perform(notif) == {:ok, [:ok, :ok]}
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag capture_log: true
|
@tag capture_log: true
|
||||||
test "returns error if notif does not match " do
|
test "returns error if notif does not match " do
|
||||||
assert Impl.perform(%{}) == :error
|
assert Impl.perform(%{}) == {:error, :unknown_type}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "successful message sending" do
|
test "successful message sending" do
|
||||||
|
|
|
@ -28,6 +28,42 @@ defmodule Pleroma.Web.StreamerTest do
|
||||||
{:ok, %{user: user, notify: notify}}
|
{:ok, %{user: user, notify: notify}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it streams the user's post in the 'user' stream", %{user: user} do
|
||||||
|
task =
|
||||||
|
Task.async(fn ->
|
||||||
|
assert_receive {:text, _}, @streamer_timeout
|
||||||
|
end)
|
||||||
|
|
||||||
|
Streamer.add_socket(
|
||||||
|
"user",
|
||||||
|
%{transport_pid: task.pid, assigns: %{user: user}}
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
|
||||||
|
|
||||||
|
Streamer.stream("user", activity)
|
||||||
|
Task.await(task)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it streams boosts of the user in the 'user' stream", %{user: user} do
|
||||||
|
task =
|
||||||
|
Task.async(fn ->
|
||||||
|
assert_receive {:text, _}, @streamer_timeout
|
||||||
|
end)
|
||||||
|
|
||||||
|
Streamer.add_socket(
|
||||||
|
"user",
|
||||||
|
%{transport_pid: task.pid, assigns: %{user: user}}
|
||||||
|
)
|
||||||
|
|
||||||
|
other_user = insert(:user)
|
||||||
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
|
||||||
|
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
|
||||||
|
|
||||||
|
Streamer.stream("user", announce)
|
||||||
|
Task.await(task)
|
||||||
|
end
|
||||||
|
|
||||||
test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
|
test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
|
||||||
task =
|
task =
|
||||||
Task.async(fn ->
|
Task.async(fn ->
|
||||||
|
|
|
@ -95,6 +95,30 @@ test "requires 'follow' or 'write:follows' permissions" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it imports follows with different nickname variations", %{conn: conn} do
|
||||||
|
[user2, user3, user4, user5, user6] = insert_list(5, :user)
|
||||||
|
|
||||||
|
identifiers =
|
||||||
|
[
|
||||||
|
user2.ap_id,
|
||||||
|
user3.nickname,
|
||||||
|
" ",
|
||||||
|
"@" <> user4.nickname,
|
||||||
|
user5.nickname <> "@localhost",
|
||||||
|
"@" <> user6.nickname <> "@localhost"
|
||||||
|
]
|
||||||
|
|> Enum.join("\n")
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post("/api/pleroma/follow_import", %{"list" => identifiers})
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert response == "job started"
|
||||||
|
assert [{:ok, job_result}] = ObanHelpers.perform_all()
|
||||||
|
assert job_result == [user2, user3, user4, user5, user6]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /api/pleroma/blocks_import" do
|
describe "POST /api/pleroma/blocks_import" do
|
||||||
|
@ -136,6 +160,29 @@ test "it imports blocks users from file", %{user: user1, conn: conn} do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it imports blocks with different nickname variations", %{conn: conn} do
|
||||||
|
[user2, user3, user4, user5, user6] = insert_list(5, :user)
|
||||||
|
|
||||||
|
identifiers =
|
||||||
|
[
|
||||||
|
user2.ap_id,
|
||||||
|
user3.nickname,
|
||||||
|
"@" <> user4.nickname,
|
||||||
|
user5.nickname <> "@localhost",
|
||||||
|
"@" <> user6.nickname <> "@localhost"
|
||||||
|
]
|
||||||
|
|> Enum.join(" ")
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post("/api/pleroma/blocks_import", %{"list" => identifiers})
|
||||||
|
|> json_response(:ok)
|
||||||
|
|
||||||
|
assert response == "job started"
|
||||||
|
assert [{:ok, job_result}] = ObanHelpers.perform_all()
|
||||||
|
assert job_result == [user2, user3, user4, user5, user6]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "PUT /api/pleroma/notification_settings" do
|
describe "PUT /api/pleroma/notification_settings" do
|
||||||
|
|
Loading…
Reference in New Issue