Browse Source

Merge

develop
Dashie der otter 1 year ago
parent
commit
8fd022c34d
25 changed files with 927 additions and 646 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +2
    -0
      config/config.exs
  3. +36
    -0
      config/description.exs
  4. +15
    -0
      docs/config.md
  5. +1
    -0
      installation/pleroma.nginx
  6. +54
    -0
      lib/pleroma/plugs/remote_ip.ex
  7. +1
    -1
      lib/pleroma/web/common_api/activity_draft.ex
  8. +1
    -4
      lib/pleroma/web/endpoint.ex
  9. +26
    -0
      lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
  10. +72
    -0
      lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
  11. +49
    -0
      lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
  12. +0
    -162
      lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
  13. +51
    -0
      lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
  14. +4
    -0
      lib/pleroma/web/mastodon_api/controllers/status_controller.ex
  15. +7
    -16
      lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
  16. +15
    -15
      lib/pleroma/web/router.ex
  17. +3
    -0
      mix.exs
  18. +2
    -0
      mix.lock
  19. +72
    -0
      test/plugs/remote_ip_test.exs
  20. +51
    -0
      test/web/mastodon_api/controllers/domain_block_controller_test.exs
  21. +137
    -0
      test/web/mastodon_api/controllers/filter_controller_test.exs
  22. +81
    -0
      test/web/mastodon_api/controllers/follow_request_controller_test.exs
  23. +113
    -0
      test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs
  24. +133
    -0
      test/web/mastodon_api/controllers/status_controller_test.exs
  25. +0
    -448
      test/web/mastodon_api/mastodon_api_controller_test.exs

+ 1
- 0
CHANGELOG.md View File

@@ -113,6 +113,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
- Pleroma API: Email change endpoint.
- Admin API: Added moderation log
- Support for `X-Forwarded-For` and similar HTTP headers which used by reverse proxies to pass a real user IP address to the backend. Must not be enabled unless your instance is behind at least one reverse proxy (such as Nginx, Apache HTTPD or Varnish Cache).
- Web response cache (currently, enabled for ActivityPub)
- Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`)
- ActivityPub: Add ActivityPub actor's `discoverable` parameter.


+ 2
- 0
config/config.exs View File

@@ -591,6 +591,8 @@ config :pleroma, :rate_limit, nil

config :pleroma, Pleroma.ActivityExpiration, enabled: true

config :pleroma, Pleroma.Plugs.RemoteIp, enabled: false

config :pleroma, :web_cache_ttl,
activity_pub: nil,
activity_pub_question: 30_000


+ 36
- 0
config/description.exs View File

@@ -2687,6 +2687,42 @@ config :pleroma, :config_description, [
}
]
},
%{
group: :pleroma,
key: Pleroma.Plugs.RemoteIp,
type: :group,
description: """
**If your instance is not behind at least one reverse proxy, you should not enable this plug.**

`Pleroma.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
""",
children: [
%{
key: :enabled,
type: :boolean,
description: "Enable/disable the plug. Defaults to `false`.",
suggestions: [true, false]
},
%{
key: :headers,
type: {:list, :string},
description:
"A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`."
},
%{
key: :proxies,
type: {:list, :string},
description:
"A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`."
},
%{
key: :reserved,
type: {:list, :string},
description:
"Defaults to [localhost](https://en.wikipedia.org/wiki/Localhost) and [private network](https://en.wikipedia.org/wiki/Private_network)."
}
]
},
%{
group: :pleroma,
key: :web_cache_ttl,


+ 15
- 0
docs/config.md View File

@@ -730,6 +730,8 @@ This will probably take a long time.

This is an advanced feature and disabled by default.

If your instance is behind a reverse proxy you must enable and configure [`Pleroma.Plugs.RemoteIp`](#pleroma-plugs-remoteip).

A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where:

* The first element: `scale` (Integer). The time scale in milliseconds.
@@ -756,3 +758,16 @@ Available caches:

* `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration).
* `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds).

## Pleroma.Plugs.RemoteIp

**If your instance is not behind at least one reverse proxy, you should not enable this plug.**

`Pleroma.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.

Available options:

* `enabled` - Enable/disable the plug. Defaults to `false`.
* `headers` - A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`.
* `proxies` - A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`.
* `reserved` - Defaults to [localhost](https://en.wikipedia.org/wiki/Localhost) and [private network](https://en.wikipedia.org/wiki/Private_network).

+ 1
- 0
installation/pleroma.nginx View File

@@ -70,6 +70,7 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only
# and `localhost.` resolves to [::0] on some systems: see issue #930


+ 54
- 0
lib/pleroma/plugs/remote_ip.ex View File

@@ -0,0 +1,54 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Plugs.RemoteIp do
@moduledoc """
This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
"""

@behaviour Plug

@headers ~w[
forwarded
x-forwarded-for
x-client-ip
x-real-ip
]

# https://en.wikipedia.org/wiki/Localhost
# https://en.wikipedia.org/wiki/Private_network
@reserved ~w[
127.0.0.0/8
::1/128
fc00::/7
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
]

def init(_), do: nil

def call(conn, _) do
config = Pleroma.Config.get(__MODULE__, [])

if Keyword.get(config, :enabled, false) do
RemoteIp.call(conn, remote_ip_opts(config))
else
conn
end
end

defp remote_ip_opts(config) do
headers = config |> Keyword.get(:headers, @headers) |> MapSet.new()
reserved = Keyword.get(config, :reserved, @reserved)

proxies =
config
|> Keyword.get(:proxies, [])
|> Enum.concat(reserved)
|> Enum.map(&InetCidr.parse/1)

{headers, proxies}
end
end

+ 1
- 1
lib/pleroma/web/common_api/activity_draft.ex View File

@@ -40,11 +40,11 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|> put_params(params)
|> status()
|> summary()
|> with_valid(&attachments/1)
|> full_payload()
|> expires_at()
|> poll()
|> with_valid(&in_reply_to/1)
|> with_valid(&attachments/1)
|> with_valid(&in_reply_to_conversation/1)
|> with_valid(&visibility/1)
|> content()


+ 1
- 4
lib/pleroma/web/endpoint.ex View File

@@ -98,10 +98,7 @@ defmodule Pleroma.Web.Endpoint do
extra: extra
)

# Note: the plug and its configuration is compile-time this can't be upstreamed yet
if proxies = Pleroma.Config.get([__MODULE__, :reverse_proxies]) do
plug(RemoteIp, proxies: proxies)
end
plug(Pleroma.Plugs.RemoteIp)

defmodule Instrumenter do
use Prometheus.PhoenixInstrumenter


+ 26
- 0
lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex View File

@@ -0,0 +1,26 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
use Pleroma.Web, :controller

alias Pleroma.User

@doc "GET /api/v1/domain_blocks"
def index(%{assigns: %{user: %{info: info}}} = conn, _) do
json(conn, Map.get(info, :domain_blocks, []))
end

@doc "POST /api/v1/domain_blocks"
def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.block_domain(blocker, domain)
json(conn, %{})
end

@doc "DELETE /api/v1/domain_blocks"
def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end
end

+ 72
- 0
lib/pleroma/web/mastodon_api/controllers/filter_controller.ex View File

@@ -0,0 +1,72 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.FilterController do
use Pleroma.Web, :controller

alias Pleroma.Filter

@doc "GET /api/v1/filters"
def index(%{assigns: %{user: user}} = conn, _) do
filters = Filter.get_filters(user)

render(conn, "filters.json", filters: filters)
end

@doc "POST /api/v1/filters"
def create(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context} = params
) do
query = %Filter{
user_id: user.id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", false),
whole_word: Map.get(params, "boolean", true)
# expires_at
}

{:ok, response} = Filter.create(query)

render(conn, "filter.json", filter: response)
end

@doc "GET /api/v1/filters/:id"
def show(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do
filter = Filter.get(filter_id, user)

render(conn, "filter.json", filter: filter)
end

@doc "PUT /api/v1/filters/:id"
def update(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context, "id" => filter_id} = params
) do
query = %Filter{
user_id: user.id,
filter_id: filter_id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", nil),
whole_word: Map.get(params, "boolean", true)
# expires_at
}

{:ok, response} = Filter.update(query)
render(conn, "filter.json", filter: response)
end

@doc "DELETE /api/v1/filters/:id"
def delete(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do
query = %Filter{
user_id: user.id,
filter_id: filter_id
}

{:ok, _} = Filter.delete(query)
json(conn, %{})
end
end

+ 49
- 0
lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex View File

@@ -0,0 +1,49 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
use Pleroma.Web, :controller

alias Pleroma.User
alias Pleroma.Web.CommonAPI

plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)
plug(:assign_follower when action != :index)

action_fallback(:errors)

@doc "GET /api/v1/follow_requests"
def index(%{assigns: %{user: followed}} = conn, _params) do
follow_requests = User.get_follow_requests(followed)

render(conn, "accounts.json", for: followed, users: follow_requests, as: :user)
end

@doc "POST /api/v1/follow_requests/:id/authorize"
def authorize(%{assigns: %{user: followed, follower: follower}} = conn, _params) do
with {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
render(conn, "relationship.json", user: followed, target: follower)
end
end

@doc "POST /api/v1/follow_requests/:id/reject"
def reject(%{assigns: %{user: followed, follower: follower}} = conn, _params) do
with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
render(conn, "relationship.json", user: followed, target: follower)
end
end

defp assign_follower(%{params: %{"id" => id}} = conn, _) do
case User.get_cached_by_id(id) do
%User{} = follower -> assign(conn, :follower, follower)
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
end
end

defp errors(conn, {:error, message}) do
conn
|> put_status(:forbidden)
|> json(%{error: message})
end
end

+ 0
- 162
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex View File

@@ -14,13 +14,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Config
alias Pleroma.Conversation.Participation
alias Pleroma.Emoji
alias Pleroma.Filter
alias Pleroma.HTTP
alias Pleroma.Object
alias Pleroma.Pagination
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
@@ -30,12 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.AppView
alias Pleroma.Web.MastodonAPI.ConversationView
alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.MastodonAPI.MastodonView
alias Pleroma.Web.MastodonAPI.ReportView
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.OAuth.App
@@ -396,55 +392,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end

def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do
with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
conn
|> add_link_headers(scheduled_activities)
|> put_view(ScheduledActivityView)
|> render("index.json", %{scheduled_activities: scheduled_activities})
end
end

def show_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
with %ScheduledActivity{} = scheduled_activity <-
ScheduledActivity.get(user, scheduled_activity_id) do
conn
|> put_view(ScheduledActivityView)
|> render("show.json", %{scheduled_activity: scheduled_activity})
else
_ -> {:error, :not_found}
end
end

def update_scheduled_status(
%{assigns: %{user: user}} = conn,
%{"id" => scheduled_activity_id} = params
) do
with %ScheduledActivity{} = scheduled_activity <-
ScheduledActivity.get(user, scheduled_activity_id),
{:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
conn
|> put_view(ScheduledActivityView)
|> render("show.json", %{scheduled_activity: scheduled_activity})
else
nil -> {:error, :not_found}
error -> error
end
end

def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
with %ScheduledActivity{} = scheduled_activity <-
ScheduledActivity.get(user, scheduled_activity_id),
{:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do
conn
|> put_view(ScheduledActivityView)
|> render("show.json", %{scheduled_activity: scheduled_activity})
else
nil -> {:error, :not_found}
error -> error
end
end

def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
id = List.wrap(id)
q = from(u in User, where: u.id in ^id)
@@ -550,42 +497,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end

def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
follow_requests = User.get_follow_requests(followed)

conn
|> put_view(AccountView)
|> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
end

def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
with %User{} = follower <- User.get_cached_by_id(id),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
else
{:error, message} ->
conn
|> put_status(:forbidden)
|> json(%{error: message})
end
end

def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
with %User{} = follower <- User.get_cached_by_id(id),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
else
{:error, message} ->
conn
|> put_status(:forbidden)
|> json(%{error: message})
end
end

def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
{_, true} <- {:followed, follower.id != followed.id},
@@ -715,20 +626,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end

def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do
json(conn, info.domain_blocks || [])
end

def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.block_domain(blocker, domain)
json(conn, %{})
end

def unblock_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end

def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %User{} = subscription_target <- User.get_cached_by_id(id),
{:ok, subscription_target} = User.subscribe(user, subscription_target) do
@@ -1040,65 +937,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
end

def get_filters(%{assigns: %{user: user}} = conn, _) do
filters = Filter.get_filters(user)
res = FilterView.render("filters.json", filters: filters)
json(conn, res)
end

def create_filter(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context} = params
) do
query = %Filter{
user_id: user.id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", false),
whole_word: Map.get(params, "boolean", true)
# expires_at
}

{:ok, response} = Filter.create(query)
res = FilterView.render("filter.json", filter: response)
json(conn, res)
end

def get_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do
filter = Filter.get(filter_id, user)
res = FilterView.render("filter.json", filter: filter)
json(conn, res)
end

def update_filter(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context, "id" => filter_id} = params
) do
query = %Filter{
user_id: user.id,
filter_id: filter_id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", nil),
whole_word: Map.get(params, "boolean", true)
# expires_at
}

{:ok, response} = Filter.update(query)
res = FilterView.render("filter.json", filter: response)
json(conn, res)
end

def delete_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do
query = %Filter{
user_id: user.id,
filter_id: filter_id
}

{:ok, _} = Filter.delete(query)
json(conn, %{})
end

def suggestions(%{assigns: %{user: user}} = conn, _) do
suggestions = Config.get(:suggestions)



+ 51
- 0
lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex View File

@@ -0,0 +1,51 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]

alias Pleroma.ScheduledActivity
alias Pleroma.Web.MastodonAPI.MastodonAPI

plug(:assign_scheduled_activity when action != :index)

action_fallback(Pleroma.Web.MastodonAPI.FallbackController)

@doc "GET /api/v1/scheduled_statuses"
def index(%{assigns: %{user: user}} = conn, params) do
with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
conn
|> add_link_headers(scheduled_activities)
|> render("index.json", scheduled_activities: scheduled_activities)
end
end

@doc "GET /api/v1/scheduled_statuses/:id"
def show(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do
render(conn, "show.json", scheduled_activity: scheduled_activity)
end

@doc "PUT /api/v1/scheduled_statuses/:id"
def update(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, params) do
with {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
render(conn, "show.json", scheduled_activity: scheduled_activity)
end
end

@doc "DELETE /api/v1/scheduled_statuses/:id"
def delete(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do
with {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do
render(conn, "show.json", scheduled_activity: scheduled_activity)
end
end

defp assign_scheduled_activity(%{assigns: %{user: user}, params: %{"id" => id}} = conn, _) do
case ScheduledActivity.get(user, id) do
%ScheduledActivity{} = activity -> assign(conn, :scheduled_activity, activity)
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
end
end
end

+ 4
- 0
lib/pleroma/web/mastodon_api/controllers/status_controller.ex View File

@@ -103,6 +103,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
end

def create(%{assigns: %{user: _user}} = conn, %{"media_ids" => _} = params) do
create(conn, Map.put(params, "status", ""))
end

@doc "GET /api/v1/statuses/:id"
def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),


+ 7
- 16
lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex View File

@@ -7,11 +7,10 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do

alias Pleroma.ScheduledActivity
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
alias Pleroma.Web.MastodonAPI.StatusView

def render("index.json", %{scheduled_activities: scheduled_activities}) do
render_many(scheduled_activities, ScheduledActivityView, "show.json")
render_many(scheduled_activities, __MODULE__, "show.json")
end

def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do
@@ -24,12 +23,8 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
end

defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do
try do
attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
Map.put(data, :media_attachments, attachments)
rescue
_ -> data
end
attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
Map.put(data, :media_attachments, attachments)
end

defp with_media_attachments(data, _), do: data
@@ -45,13 +40,9 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
in_reply_to_id: params["in_reply_to_id"]
}

data =
if media_ids = params["media_ids"] do
Map.put(data, :media_ids, media_ids)
else
data
end

data
case params["media_ids"] do
nil -> data
media_ids -> Map.put(data, :media_ids, media_ids)
end
end
end

+ 15
- 15
lib/pleroma/web/router.ex View File

@@ -323,7 +323,7 @@ defmodule Pleroma.Web.Router do
get("/accounts/:id/lists", MastodonAPIController, :account_lists)
get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)

get("/follow_requests", MastodonAPIController, :follow_requests)
get("/follow_requests", FollowRequestController, :index)
get("/blocks", MastodonAPIController, :blocks)
get("/mutes", MastodonAPIController, :mutes)

@@ -339,16 +339,16 @@ defmodule Pleroma.Web.Router do
post("/notifications/dismiss", NotificationController, :dismiss)
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)

get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses)
get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status)
get("/scheduled_statuses", ScheduledActivityController, :index)
get("/scheduled_statuses/:id", ScheduledActivityController, :show)

get("/lists", ListController, :index)
get("/lists/:id", ListController, :show)
get("/lists/:id/accounts", ListController, :list_accounts)

get("/domain_blocks", MastodonAPIController, :domain_blocks)
get("/domain_blocks", DomainBlockController, :index)

get("/filters", MastodonAPIController, :get_filters)
get("/filters", FilterController, :index)

get("/suggestions", MastodonAPIController, :suggestions)

@@ -377,8 +377,8 @@ defmodule Pleroma.Web.Router do
post("/statuses/:id/mute", StatusController, :mute_conversation)
post("/statuses/:id/unmute", StatusController, :unmute_conversation)

put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status)
delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status)
put("/scheduled_statuses/:id", ScheduledActivityController, :update)
delete("/scheduled_statuses/:id", ScheduledActivityController, :delete)

post("/polls/:id/votes", MastodonAPIController, :poll_vote)

@@ -392,10 +392,10 @@ defmodule Pleroma.Web.Router do
post("/lists/:id/accounts", ListController, :add_to_list)
delete("/lists/:id/accounts", ListController, :remove_from_list)

post("/filters", MastodonAPIController, :create_filter)
get("/filters/:id", MastodonAPIController, :get_filter)
put("/filters/:id", MastodonAPIController, :update_filter)
delete("/filters/:id", MastodonAPIController, :delete_filter)
post("/filters", FilterController, :create)
get("/filters/:id", FilterController, :show)
put("/filters/:id", FilterController, :update)
delete("/filters/:id", FilterController, :delete)

patch("/pleroma/accounts/update_avatar", MastodonAPIController, :update_avatar)
patch("/pleroma/accounts/update_banner", MastodonAPIController, :update_banner)
@@ -419,11 +419,11 @@ defmodule Pleroma.Web.Router do
post("/accounts/:id/mute", MastodonAPIController, :mute)
post("/accounts/:id/unmute", MastodonAPIController, :unmute)

post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request)
post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request)
post("/follow_requests/:id/authorize", FollowRequestController, :authorize)
post("/follow_requests/:id/reject", FollowRequestController, :reject)

post("/domain_blocks", MastodonAPIController, :block_domain)
delete("/domain_blocks", MastodonAPIController, :unblock_domain)
post("/domain_blocks", DomainBlockController, :create)
delete("/domain_blocks", DomainBlockController, :delete)

post("/pleroma/accounts/:id/subscribe", MastodonAPIController, :subscribe)
post("/pleroma/accounts/:id/unsubscribe", MastodonAPIController, :unsubscribe)


+ 3
- 0
mix.exs View File

@@ -160,6 +160,9 @@ defmodule Pleroma.Mixfile do
{:plug_static_index_html, "~> 1.0.0"},
{:excoveralls, "~> 0.11.1", only: :test},
{:flake_id, "~> 0.1.0"},
{:remote_ip,
git: "https://git.pleroma.social/pleroma/remote_ip.git",
ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"},
{:mox, "~> 0.5", only: :test}
] ++ oauth_deps()
end


+ 2
- 0
mix.lock View File

@@ -48,6 +48,7 @@
"http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]},
"httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"joken": {:hex, :joken, "2.0.1", "ec9ab31bf660f343380da033b3316855197c8d4c6ef597fa3fcb451b326beb14", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"},
"jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
@@ -88,6 +89,7 @@
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]},
"sentry": {:hex, :sentry, "7.0.5", "31531b7218d6932dc32c4180a153ec9c2485da019868c666190bca522ce083c8", [:mix], [{:hackney, "~> 1.8 or 1.6.5", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "825dc00aaba5a1b7c4202a532b696b595dd3bcb3", [ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"]},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"},
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"},


+ 72
- 0
test/plugs/remote_ip_test.exs View File

@@ -0,0 +1,72 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Plugs.RemoteIpTest do
use ExUnit.Case, async: true
use Plug.Test

alias Pleroma.Plugs.RemoteIp

test "disabled" do
Pleroma.Config.put(RemoteIp, enabled: false)

%{remote_ip: remote_ip} = conn(:get, "/")

conn =
conn(:get, "/")
|> put_req_header("x-forwarded-for", "1.1.1.1")
|> RemoteIp.call(nil)

assert conn.remote_ip == remote_ip
end

test "enabled" do
Pleroma.Config.put(RemoteIp, enabled: true)

conn =
conn(:get, "/")
|> put_req_header("x-forwarded-for", "1.1.1.1")
|> RemoteIp.call(nil)

assert conn.remote_ip == {1, 1, 1, 1}
end

test "custom headers" do
Pleroma.Config.put(RemoteIp, enabled: true, headers: ["cf-connecting-ip"])

conn =
conn(:get, "/")
|> put_req_header("x-forwarded-for", "1.1.1.1")
|> RemoteIp.call(nil)

refute conn.remote_ip == {1, 1, 1, 1}

conn =
conn(:get, "/")
|> put_req_header("cf-connecting-ip", "1.1.1.1")
|> RemoteIp.call(nil)

assert conn.remote_ip == {1, 1, 1, 1}
end

test "custom proxies" do
Pleroma.Config.put(RemoteIp, enabled: true)

conn =
conn(:get, "/")
|> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
|> RemoteIp.call(nil)

refute conn.remote_ip == {1, 1, 1, 1}

Pleroma.Config.put([RemoteIp, :proxies], ["173.245.48.0/20"])

conn =
conn(:get, "/")
|> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
|> RemoteIp.call(nil)

assert conn.remote_ip == {1, 1, 1, 1}
end
end

+ 51
- 0
test/web/mastodon_api/controllers/domain_block_controller_test.exs View File

@@ -0,0 +1,51 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
use Pleroma.Web.ConnCase, async: true

alias Pleroma.User

import Pleroma.Factory

test "blocking / unblocking a domain", %{conn: conn} do
user = insert(:user)
other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})

conn =
conn
|> assign(:user, user)
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})

assert %{} = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
assert User.blocks?(user, other_user)

conn =
build_conn()
|> assign(:user, user)
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})

assert %{} = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
refute User.blocks?(user, other_user)
end

test "getting a list of domain blocks", %{conn: conn} do
user = insert(:user)

{:ok, user} = User.block_domain(user, "bad.site")
{:ok, user} = User.block_domain(user, "even.worse.site")

conn =
conn
|> assign(:user, user)
|> get("/api/v1/domain_blocks")

domain_blocks = json_response(conn, 200)

assert "bad.site" in domain_blocks
assert "even.worse.site" in domain_blocks
end
end

+ 137
- 0
test/web/mastodon_api/controllers/filter_controller_test.exs View File

@@ -0,0 +1,137 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
use Pleroma.Web.ConnCase, async: true

alias Pleroma.Web.MastodonAPI.FilterView

import Pleroma.Factory

test "creating a filter", %{conn: conn} do
user = insert(:user)

filter = %Pleroma.Filter{
phrase: "knights",
context: ["home"]
}

conn =
conn
|> assign(:user, user)
|> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})

assert response = json_response(conn, 200)
assert response["phrase"] == filter.phrase
assert response["context"] == filter.context
assert response["irreversible"] == false
assert response["id"] != nil
assert response["id"] != ""
end

test "fetching a list of filters", %{conn: conn} do
user = insert(:user)

query_one = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "knights",
context: ["home"]
}

query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "who",
context: ["home"]
}

{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.create(query_two)

response =
conn
|> assign(:user, user)
|> get("/api/v1/filters")
|> json_response(200)

assert response ==
render_json(
FilterView,
"filters.json",
filters: [filter_two, filter_one]
)
end

test "get a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, filter} = Pleroma.Filter.create(query)

conn =
conn
|> assign(:user, user)
|> get("/api/v1/filters/#{filter.filter_id}")

assert _response = json_response(conn, 200)
end

test "update a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, _filter} = Pleroma.Filter.create(query)

new = %Pleroma.Filter{
phrase: "nii",
context: ["home"]
}

conn =
conn
|> assign(:user, user)
|> put("/api/v1/filters/#{query.filter_id}", %{
phrase: new.phrase,
context: new.context
})

assert response = json_response(conn, 200)
assert response["phrase"] == new.phrase
assert response["context"] == new.context
end

test "delete a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, filter} = Pleroma.Filter.create(query)

conn =
conn
|> assign(:user, user)
|> delete("/api/v1/filters/#{filter.filter_id}")

assert response = json_response(conn, 200)
assert response == %{}
end
end

+ 81
- 0
test/web/mastodon_api/controllers/follow_request_controller_test.exs View File

@@ -0,0 +1,81 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
use Pleroma.Web.ConnCase

alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub

import Pleroma.Factory

describe "locked accounts" do
test "/api/v1/follow_requests works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false

conn =
build_conn()
|> assign(:user, user)
|> get("/api/v1/follow_requests")

assert [relationship] = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
end

test "/api/v1/follow_requests/:id/authorize works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false

conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/follow_requests/#{other_user.id}/authorize")

assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == true
end

test "/api/v1/follow_requests/:id/reject works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)

conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/follow_requests/#{other_user.id}/reject")

assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false
end
end
end

+ 113
- 0
test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs View File

@@ -0,0 +1,113 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
use Pleroma.Web.ConnCase, async: true

alias Pleroma.Repo
alias Pleroma.ScheduledActivity

import Pleroma.Factory

test "shows scheduled activities", %{conn: conn} do
user = insert(:user)
scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()

conn =
conn
|> assign(:user, user)

# min_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result

# since_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result

# max_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
end

test "shows a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

res_conn =
conn
|> assign(:user, user)
|> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
assert scheduled_activity_id == scheduled_activity.id |> to_string()

res_conn =
conn
|> assign(:user, user)
|> get("/api/v1/scheduled_statuses/404")

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end

test "updates a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

new_scheduled_at =
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

res_conn =
conn
|> assign(:user, user)
|> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
scheduled_at: new_scheduled_at
})

assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)

res_conn =
conn
|> assign(:user, user)
|> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end

test "deletes a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

res_conn =
conn
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{} = json_response(res_conn, 200)
assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)

res_conn =
conn
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end
end

+ 133
- 0
test/web/mastodon_api/controllers/status_controller_test.exs View File

@@ -9,7 +9,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
alias Pleroma.ActivityExpiration
alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI

import Pleroma.Factory
@@ -96,6 +99,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
NaiveDateTime.to_iso8601(expiration.scheduled_at)
end

test "posting an undefined status with an attachment", %{conn: conn} do
user = insert(:user)

file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}

{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"media_ids" => [to_string(upload.id)]
})

assert json_response(conn, 200)
end

test "replying to a status", %{conn: conn} do
user = insert(:user)
{:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
@@ -224,6 +248,115 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end
end

describe "posting scheduled statuses" do
test "creates a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "scheduled",
"scheduled_at" => scheduled_at
})

assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
assert expected_scheduled_at == CommonAPI.Utils.to_masto_date(scheduled_at)
assert [] == Repo.all(Activity)
end

test "creates a scheduled activity with a media attachment", %{conn: conn} do
user = insert(:user)
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}

{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"media_ids" => [to_string(upload.id)],
"status" => "scheduled",
"scheduled_at" => scheduled_at
})

assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
assert %{"type" => "image"} = media_attachment
end

test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
%{conn: conn} do
user = insert(:user)

scheduled_at =
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "not scheduled",
"scheduled_at" => scheduled_at
})

assert %{"content" => "not scheduled"} = json_response(conn, 200)
assert [] == Repo.all(ScheduledActivity)
end

test "returns error when daily user limit is exceeded", %{conn: conn} do
user = insert(:user)

today =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|> NaiveDateTime.to_iso8601()

attrs = %{params: %{}, scheduled_at: today}
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, attrs)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})

assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
end

test "returns error when total user limit is exceeded", %{conn: conn} do
user = insert(:user)

today =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|> NaiveDateTime.to_iso8601()

tomorrow =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.hours(36), :millisecond)
|> NaiveDateTime.to_iso8601()

attrs = %{params: %{}, scheduled_at: today}
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})

assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
end
end

describe "posting polls" do
test "posting a poll", %{conn: conn} do
user = insert(:user)


+ 0
- 448
test/web/mastodon_api/mastodon_api_controller_test.exs View File

@@ -6,17 +6,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
use Pleroma.Web.ConnCase

alias Ecto.Changeset
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Push
@@ -268,134 +265,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert expected == json_response(conn, 200)
end

describe "filters" do
test "creating a filter", %{conn: conn} do
user = insert(:user)

filter = %Pleroma.Filter{
phrase: "knights",
context: ["home"]
}

conn =
conn
|> assign(:user, user)
|> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})

assert response = json_response(conn, 200)
assert response["phrase"] == filter.phrase
assert response["context"] == filter.context
assert response["irreversible"] == false
assert response["id"] != nil
assert response["id"] != ""
end

test "fetching a list of filters", %{conn: conn} do
user = insert(:user)

query_one = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "knights",
context: ["home"]
}

query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "who",
context: ["home"]
}

{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.create(query_two)

response =
conn
|> assign(:user, user)
|> get("/api/v1/filters")
|> json_response(200)

assert response ==
render_json(
FilterView,
"filters.json",
filters: [filter_two, filter_one]
)
end

test "get a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, filter} = Pleroma.Filter.create(query)

conn =
conn
|> assign(:user, user)
|> get("/api/v1/filters/#{filter.filter_id}")

assert _response = json_response(conn, 200)
end

test "update a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, _filter} = Pleroma.Filter.create(query)

new = %Pleroma.Filter{
phrase: "nii",
context: ["home"]
}

conn =
conn
|> assign(:user, user)
|> put("/api/v1/filters/#{query.filter_id}", %{
phrase: new.phrase,
context: new.context
})

assert response = json_response(conn, 200)
assert response["phrase"] == new.phrase
assert response["context"] == new.context
end

test "delete a filter", %{conn: conn} do
user = insert(:user)

query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}

{:ok, filter} = Pleroma.Filter.create(query)

conn =
conn
|> assign(:user, user)
|> delete("/api/v1/filters/#{filter.filter_id}")

assert response = json_response(conn, 200)
assert response == %{}
end
end

describe "user timelines" do
test "gets a users statuses", %{conn: conn} do
user_one = insert(:user)
@@ -570,51 +439,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end

describe "locked accounts" do
test "/api/v1/follow_requests works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false

conn =
build_conn()
|> assign(:user, user)
|> get("/api/v1/follow_requests")

assert [relationship] = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
end

test "/api/v1/follow_requests/:id/authorize works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false

conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/follow_requests/#{other_user.id}/authorize")

assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == true
end

test "verify_credentials", %{conn: conn} do
user = insert(:user, %{info: %User.Info{default_scope: "private"}})

@@ -626,28 +450,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
assert id == to_string(user.id)
end

test "/api/v1/follow_requests/:id/reject works" do
user = insert(:user, %{info: %User.Info{locked: true}})
other_user = insert(:user)

{:ok, _activity} = ActivityPub.follow(other_user, user)

user = User.get_cached_by_id(user.id)

conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/follow_requests/#{other_user.id}/reject")

assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]

user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)

assert User.following?(other_user, user) == false
end
end

describe "account fetching" do
@@ -1176,46 +978,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
end

test "blocking / unblocking a domain", %{conn: conn} do
user = insert(:user)
other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})

conn =
conn
|> assign(:user, user)
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})

assert %{} = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
assert User.blocks?(user, other_user)

conn =
build_conn()
|> assign(:user, user)
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})

assert %{} = json_response(conn, 200)
user = User.get_cached_by_ap_id(user.ap_id)
refute User.blocks?(user, other_user)
end

test "getting a list of domain blocks", %{conn: conn} do
user = insert(:user)

{:ok, user} = User.block_domain(user, "bad.site")
{:ok, user} = User.block_domain(user, "even.worse.site")

conn =
conn
|> assign(:user, user)
|> get("/api/v1/domain_blocks")

domain_blocks = json_response(conn, 200)

assert "bad.site" in domain_blocks
assert "even.worse.site" in domain_blocks
end

test "unimplemented follow_requests, blocks, domain blocks" do
user = insert(:user)

@@ -1810,216 +1572,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
end

describe "scheduled activities" do
test "creates a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "scheduled",
"scheduled_at" => scheduled_at
})

assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
assert [] == Repo.all(Activity)
end

test "creates a scheduled activity with a media attachment", %{conn: conn} do
user = insert(:user)
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}

{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"media_ids" => [to_string(upload.id)],
"status" => "scheduled",
"scheduled_at" => scheduled_at
})

assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
assert %{"type" => "image"} = media_attachment
end

test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
%{conn: conn} do
user = insert(:user)

scheduled_at =
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "not scheduled",
"scheduled_at" => scheduled_at
})

assert %{"content" => "not scheduled"} = json_response(conn, 200)
assert [] == Repo.all(ScheduledActivity)
end

test "returns error when daily user limit is exceeded", %{conn: conn} do
user = insert(:user)

today =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|> NaiveDateTime.to_iso8601()

attrs = %{params: %{}, scheduled_at: today}
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, attrs)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})

assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
end

test "returns error when total user limit is exceeded", %{conn: conn} do
user = insert(:user)

today =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|> NaiveDateTime.to_iso8601()

tomorrow =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.hours(36), :millisecond)
|> NaiveDateTime.to_iso8601()

attrs = %{params: %{}, scheduled_at: today}
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, attrs)
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})

conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})

assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
end

test "shows scheduled activities", %{conn: conn} do
user = insert(:user)
scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()

conn =
conn
|> assign(:user, user)

# min_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result

# since_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result

# max_id
conn_res =
conn
|> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")

result = json_response(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
end

test "shows a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

res_conn =
conn
|> assign(:user, user)
|> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
assert scheduled_activity_id == scheduled_activity.id |> to_string()

res_conn =
conn
|> assign(:user, user)
|> get("/api/v1/scheduled_statuses/404")

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end

test "updates a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

new_scheduled_at =
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)

res_conn =
conn
|> assign(:user, user)
|> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
scheduled_at: new_scheduled_at
})

assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)

res_conn =
conn
|> assign(:user, user)
|> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end

test "deletes a scheduled activity", %{conn: conn} do
user = insert(:user)
scheduled_activity = insert(:scheduled_activity, user: user)

res_conn =
conn
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{} = json_response(res_conn, 200)
assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)

res_conn =
conn
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")

assert %{"error" => "Record not found"} = json_response(res_conn, 404)
end
end

describe "create account by app" do
test "Account registration via Application", %{conn: conn} do
conn =


Loading…
Cancel
Save