Merge remote-tracking branch 'origin/develop' into shigusegubu

* origin/develop: (62 commits)
  update pleroma frontend
  tests: add regression test
  MRF: anti followbot: gracefully handle accounts without a display name
  Adjust delete activity audience to match the deleted object
  Revert existing object check
  Preserve parameters in link headers (Mastodon API)
  [#647] tests for web push
  Keep heading short
  Add default config for masto_fe
  Add handling of objects not in database
  Add tests for reserved char escaping in upload
  Properly escape reserved URI charachters in upload urls
  Web.RelMe: Fix having other values in rel attr
  Plugs.HTTPSecurityPlug: Add static_url to CSP's connect-src
  Include admins in nodeinfo
  Typo
  rich media: helpers: rework validate_page_url()
  local -> only_local
  Format & update docs
  helpers: use AutoLinker to validate URIs as well as the other tests
  ...
This commit is contained in:
Henry Jameson 2019-03-07 19:54:48 +02:00
commit 66185ad957
71 changed files with 1860 additions and 464 deletions

View file

@ -1,12 +0,0 @@
Unliking:
- Add a proper undo activity, find out how to ignore those in twitter api.
WEBSUB:
- Add unsubscription
OSTATUS:
- Save and output 'updated'

View file

@ -199,6 +199,9 @@ config :pleroma, :frontend_configurations,
scopeCopy: false, scopeCopy: false,
subjectLineBehavior: "noop", subjectLineBehavior: "noop",
alwaysShowSubjectInput: false alwaysShowSubjectInput: false
},
masto_fe: %{
showInstanceSpecificPanel: true
} }
config :pleroma, :activitypub, config :pleroma, :activitypub,

View file

@ -44,6 +44,8 @@ config :web_push_encryption, :vapid_details,
"BLH1qVhJItRGCfxgTtONfsOKDc9VRAraXw-3NsmjMngWSh7NxOizN6bkuRA7iLTMPS82PjwJAr3UoK9EC1IFrz4", "BLH1qVhJItRGCfxgTtONfsOKDc9VRAraXw-3NsmjMngWSh7NxOizN6bkuRA7iLTMPS82PjwJAr3UoK9EC1IFrz4",
private_key: "_-XZ0iebPrRfZ_o0-IatTdszYa8VCH1yLN-JauK7HHA" private_key: "_-XZ0iebPrRfZ_o0-IatTdszYa8VCH1yLN-JauK7HHA"
config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock
config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2] config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2]
try do try do

View file

@ -7,17 +7,26 @@ Authentication is required and the user must be an admin.
### List users ### List users
- Method `GET` - Method `GET`
- Query Params:
- `query`: **string** *optional* search term
- `local_only`: **bool** *optional* whether to return only local users
- `page`: **integer** *optional* page number
- `page_size`: **integer** *optional* number of users per page (default is `50`)
- Response: - Response:
```JSON ```JSON
[ {
"page_size": integer,
"count": integer,
"users": [
{ {
"deactivated": bool, "deactivated": bool,
"id": integer, "id": integer,
"nickname": string "nickname": string
}, },
... ...
] ]
}
``` ```
## `/api/pleroma/admin/user` ## `/api/pleroma/admin/user`
@ -49,9 +58,9 @@ Authentication is required and the user must be an admin.
```JSON ```JSON
{ {
"deactivated": bool, "deactivated": bool,
"id": integer, "id": integer,
"nickname": string "nickname": string
} }
``` ```
@ -81,8 +90,8 @@ Authentication is required and the user must be an admin.
```JSON ```JSON
{ {
"is_moderator": bool, "is_moderator": bool,
"is_admin": bool "is_admin": bool
} }
``` ```
@ -98,8 +107,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
```JSON ```JSON
{ {
"is_moderator": bool, "is_moderator": bool,
"is_admin": bool "is_admin": bool
} }
``` ```

View file

@ -129,7 +129,7 @@ See: [loggers documentation](https://hexdocs.pm/logger/Logger.html) and [ex_s
## :frontend_configurations ## :frontend_configurations
This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` are configured. This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured.
Frontends can access these settings at `/api/pleroma/frontend_configurations` Frontends can access these settings at `/api/pleroma/frontend_configurations`

View file

@ -34,13 +34,16 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
defp csp_string do defp csp_string do
scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme] scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme]
websocket_url = String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws") static_url = Pleroma.Web.Endpoint.static_url()
websocket_url = String.replace(static_url, "http", "ws")
connect_src = "connect-src 'self' #{static_url} #{websocket_url}"
connect_src = connect_src =
if Mix.env() == :dev do if Mix.env() == :dev do
"connect-src 'self' http://localhost:3035/ " <> websocket_url connect_src <> " http://localhost:3035/"
else else
"connect-src 'self' " <> websocket_url connect_src
end end
script_src = script_src =

View file

@ -85,6 +85,10 @@ defmodule Pleroma.Upload do
end end
end end
def char_unescaped?(char) do
URI.char_unreserved?(char) or char == ?/
end
defp get_opts(opts) do defp get_opts(opts) do
{size_limit, activity_type} = {size_limit, activity_type} =
case Keyword.get(opts, :type) do case Keyword.get(opts, :type) do
@ -218,9 +222,7 @@ defmodule Pleroma.Upload do
defp url_from_spec(base_url, {:file, path}) do defp url_from_spec(base_url, {:file, path}) do
path = path =
path path
|> URI.encode() |> URI.encode(&char_unescaped?/1)
|> String.replace("?", "%3F")
|> String.replace(":", "%3A")
[base_url, "media", path] [base_url, "media", path]
|> Path.join() |> Path.join()

View file

@ -22,6 +22,7 @@ defmodule Pleroma.User do
alias Pleroma.Web.OAuth alias Pleroma.Web.OAuth
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.RelMe
require Logger require Logger
@ -547,11 +548,8 @@ defmodule Pleroma.User do
end end
def get_followers_query(user, page) do def get_followers_query(user, page) do
from( from(u in get_followers_query(user, nil))
u in get_followers_query(user, nil), |> paginate(page, 20)
limit: 20,
offset: ^((page - 1) * 20)
)
end end
def get_followers_query(user), do: get_followers_query(user, nil) def get_followers_query(user), do: get_followers_query(user, nil)
@ -577,11 +575,8 @@ defmodule Pleroma.User do
end end
def get_friends_query(user, page) do def get_friends_query(user, page) do
from( from(u in get_friends_query(user, nil))
u in get_friends_query(user, nil), |> paginate(page, 20)
limit: 20,
offset: ^((page - 1) * 20)
)
end end
def get_friends_query(user), do: get_friends_query(user, nil) def get_friends_query(user), do: get_friends_query(user, nil)
@ -621,64 +616,57 @@ defmodule Pleroma.User do
) )
end end
def update_follow_request_count(%User{} = user) do def get_follow_requests(%User{} = user) do
subquery = users =
user user
|> User.get_follow_requests_query() |> User.get_follow_requests_query()
|> select([a], %{count: count(a.id)}) |> join(:inner, [a], u in User, a.actor == u.ap_id)
|> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
User |> group_by([a, u], u.id)
|> where(id: ^user.id) |> select([a, u], u)
|> join(:inner, [u], s in subquery(subquery)) |> Repo.all()
|> update([u, s],
set: [
info:
fragment(
"jsonb_set(?, '{follow_request_count}', ?::varchar::jsonb, true)",
u.info,
s.count
)
]
)
|> Repo.update_all([], returning: true)
|> case do
{1, [user]} -> {:ok, user}
_ -> {:error, user}
end
end
def get_follow_requests(%User{} = user) do
q = get_follow_requests_query(user)
reqs = Repo.all(q)
users =
Enum.map(reqs, fn req -> req.actor end)
|> Enum.uniq()
|> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
|> Enum.filter(fn u -> !is_nil(u) end)
|> Enum.filter(fn u -> !following?(u, user) end)
{:ok, users} {:ok, users}
end end
def increase_note_count(%User{} = user) do def increase_note_count(%User{} = user) do
info_cng = User.Info.add_to_note_count(user.info, 1) User
|> where(id: ^user.id)
cng = |> update([u],
change(user) set: [
|> put_embed(:info, info_cng) info:
fragment(
update_and_set_cache(cng) "jsonb_set(?, '{note_count}', ((?->>'note_count')::int + 1)::varchar::jsonb, true)",
u.info,
u.info
)
]
)
|> Repo.update_all([], returning: true)
|> case do
{1, [user]} -> set_cache(user)
_ -> {:error, user}
end
end end
def decrease_note_count(%User{} = user) do def decrease_note_count(%User{} = user) do
info_cng = User.Info.add_to_note_count(user.info, -1) User
|> where(id: ^user.id)
cng = |> update([u],
change(user) set: [
|> put_embed(:info, info_cng) info:
fragment(
update_and_set_cache(cng) "jsonb_set(?, '{note_count}', (greatest(0, (?->>'note_count')::int - 1))::varchar::jsonb, true)",
u.info,
u.info
)
]
)
|> Repo.update_all([], returning: true)
|> case do
{1, [user]} -> set_cache(user)
_ -> {:error, user}
end
end end
def update_note_count(%User{} = user) do def update_note_count(%User{} = user) do
@ -702,24 +690,29 @@ defmodule Pleroma.User do
def update_follower_count(%User{} = user) do def update_follower_count(%User{} = user) do
follower_count_query = follower_count_query =
from( User
u in User, |> where([u], ^user.follower_address in u.following)
where: ^user.follower_address in u.following, |> where([u], u.id != ^user.id)
where: u.id != ^user.id, |> select([u], %{count: count(u.id)})
select: count(u.id)
)
follower_count = Repo.one(follower_count_query) User
|> where(id: ^user.id)
info_cng = |> join(:inner, [u], s in subquery(follower_count_query))
user.info |> update([u, s],
|> User.Info.set_follower_count(follower_count) set: [
info:
cng = fragment(
change(user) "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)",
|> put_embed(:info, info_cng) u.info,
s.count
update_and_set_cache(cng) )
]
)
|> Repo.update_all([], returning: true)
|> case do
{1, [user]} -> set_cache(user)
_ -> {:error, user}
end
end end
def get_users_from_set_query(ap_ids, false) do def get_users_from_set_query(ap_ids, false) do
@ -756,6 +749,59 @@ defmodule Pleroma.User do
Repo.all(query) Repo.all(query)
end end
@spec search_for_admin(%{
local: boolean(),
page: number(),
page_size: number()
}) :: {:ok, [Pleroma.User.t()], number()}
def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
query =
from(u in User, order_by: u.id)
|> maybe_local_user_query(local)
paginated_query =
query
|> paginate(page, page_size)
count =
query
|> Repo.aggregate(:count, :id)
{:ok, Repo.all(paginated_query), count}
end
@spec search_for_admin(%{
query: binary(),
admin: Pleroma.User.t(),
local: boolean(),
page: number(),
page_size: number()
}) :: {:ok, [Pleroma.User.t()], number()}
def search_for_admin(%{
query: term,
admin: admin,
local: local,
page: page,
page_size: page_size
}) do
term = String.trim_leading(term, "@")
local_paginated_query =
User
|> maybe_local_user_query(local)
|> paginate(page, page_size)
search_query = fts_search_subquery(term, local_paginated_query)
count =
term
|> fts_search_subquery()
|> maybe_local_user_query(local)
|> Repo.aggregate(:count, :id)
{:ok, do_search(search_query, admin), count}
end
def search(query, resolve \\ false, for_user \\ nil) do def search(query, resolve \\ false, for_user \\ nil) do
# Strip the beginning @ off if there is a query # Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@") query = String.trim_leading(query, "@")
@ -773,12 +819,6 @@ defmodule Pleroma.User do
Enum.uniq_by(fts_results ++ trigram_results, & &1.id) Enum.uniq_by(fts_results ++ trigram_results, & &1.id)
end end
def all_except_one(user) do
query = from(u in User, where: u.id != ^user.id)
Repo.all(query)
end
defp do_search(subquery, for_user, options \\ []) do defp do_search(subquery, for_user, options \\ []) do
q = q =
from( from(
@ -795,9 +835,9 @@ defmodule Pleroma.User do
boost_search_results(results, for_user) boost_search_results(results, for_user)
end end
defp fts_search_subquery(query) do defp fts_search_subquery(term, query \\ User) do
processed_query = processed_query =
query term
|> String.replace(~r/\W+/, " ") |> String.replace(~r/\W+/, " ")
|> String.trim() |> String.trim()
|> String.split() |> String.split()
@ -805,7 +845,7 @@ defmodule Pleroma.User do
|> Enum.join(" | ") |> Enum.join(" | ")
from( from(
u in User, u in query,
select_merge: %{ select_merge: %{
search_rank: search_rank:
fragment( fragment(
@ -835,19 +875,19 @@ defmodule Pleroma.User do
) )
end end
defp trigram_search_subquery(query) do defp trigram_search_subquery(term) do
from( from(
u in User, u in User,
select_merge: %{ select_merge: %{
search_rank: search_rank:
fragment( fragment(
"similarity(?, trim(? || ' ' || coalesce(?, '')))", "similarity(?, trim(? || ' ' || coalesce(?, '')))",
^query, ^term,
u.nickname, u.nickname,
u.name u.name
) )
}, },
where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^query) where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term)
) )
end end
@ -1005,9 +1045,13 @@ defmodule Pleroma.User do
update_and_set_cache(cng) update_and_set_cache(cng)
end end
def local_user_query do def maybe_local_user_query(query, local) do
if local, do: local_user_query(query), else: query
end
def local_user_query(query \\ User) do
from( from(
u in User, u in query,
where: u.local == true, where: u.local == true,
where: not is_nil(u.nickname) where: not is_nil(u.nickname)
) )
@ -1202,8 +1246,14 @@ defmodule Pleroma.User do
{String.trim(name, ":"), url} {String.trim(name, ":"), url}
end) end)
# TODO: get profile URLs other than user.ap_id
profile_urls = [user.ap_id]
bio bio
|> CommonUtils.format_input("text/plain", mentions_format: :full) |> CommonUtils.format_input("text/plain",
mentions_format: :full,
rel: &RelMe.maybe_put_rel_me(&1, profile_urls)
)
|> elem(0) |> elem(0)
|> Formatter.emojify(emoji) |> Formatter.emojify(emoji)
end end
@ -1299,4 +1349,11 @@ defmodule Pleroma.User do
) )
|> Repo.all() |> Repo.all()
end end
defp paginate(query, page, page_size) do
from(u in query,
limit: ^page_size,
offset: ^((page - 1) * page_size)
)
end
end end

View file

@ -12,7 +12,6 @@ defmodule Pleroma.User.Info do
field(:source_data, :map, default: %{}) field(:source_data, :map, default: %{})
field(:note_count, :integer, default: 0) field(:note_count, :integer, default: 0)
field(:follower_count, :integer, default: 0) field(:follower_count, :integer, default: 0)
field(:follow_request_count, :integer, default: 0)
field(:locked, :boolean, default: false) field(:locked, :boolean, default: false)
field(:confirmation_pending, :boolean, default: false) field(:confirmation_pending, :boolean, default: false)
field(:confirmation_token, :string, default: nil) field(:confirmation_token, :string, default: nil)

View file

@ -81,6 +81,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp check_remote_limit(_), do: true defp check_remote_limit(_), do: true
def increase_note_count_if_public(actor, object) do
if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
end
def decrease_note_count_if_public(actor, object) do
if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
end
def insert(map, local \\ true) when is_map(map) do def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.normalize(map), with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map), map <- lazy_put_activity_defaults(map),
@ -163,7 +171,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
), ),
{:ok, activity} <- insert(create_data, local), {:ok, activity} <- insert(create_data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
{:ok, _actor} <- User.increase_note_count(actor), {:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity} {:ok, activity}
end end
@ -175,8 +183,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
with data <- %{"to" => to, "type" => "Accept", "actor" => actor.ap_id, "object" => object}, with data <- %{"to" => to, "type" => "Accept", "actor" => actor.ap_id, "object" => object},
{:ok, activity} <- insert(data, local), {:ok, activity} <- insert(data, local),
:ok <- maybe_federate(activity), :ok <- maybe_federate(activity) do
_ <- User.update_follow_request_count(actor) do
{:ok, activity} {:ok, activity}
end end
end end
@ -187,8 +194,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
with data <- %{"to" => to, "type" => "Reject", "actor" => actor.ap_id, "object" => object}, with data <- %{"to" => to, "type" => "Reject", "actor" => actor.ap_id, "object" => object},
{:ok, activity} <- insert(data, local), {:ok, activity} <- insert(data, local),
:ok <- maybe_federate(activity), :ok <- maybe_federate(activity) do
_ <- User.update_follow_request_count(actor) do
{:ok, activity} {:ok, activity}
end end
end end
@ -286,8 +292,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def follow(follower, followed, activity_id \\ nil, local \\ true) do def follow(follower, followed, activity_id \\ nil, local \\ true) do
with data <- make_follow_data(follower, followed, activity_id), with data <- make_follow_data(follower, followed, activity_id),
{:ok, activity} <- insert(data, local), {:ok, activity} <- insert(data, local),
:ok <- maybe_federate(activity), :ok <- maybe_federate(activity) do
_ <- User.update_follow_request_count(followed) do
{:ok, activity} {:ok, activity}
end end
end end
@ -297,26 +302,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"), {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id), unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
{:ok, activity} <- insert(unfollow_data, local), {:ok, activity} <- insert(unfollow_data, local),
:ok <- maybe_federate(activity), :ok <- maybe_federate(activity) do
_ <- User.update_follow_request_count(followed) do
{:ok, activity} {:ok, activity}
end end
end end
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor) user = User.get_cached_by_ap_id(actor)
to = object.data["to"] || [] ++ object.data["cc"] || []
data = %{ data = %{
"type" => "Delete", "type" => "Delete",
"actor" => actor, "actor" => actor,
"object" => id, "object" => id,
"to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"] "to" => to
} }
with {:ok, _} <- Object.delete(object), with {:ok, _} <- Object.delete(object),
{:ok, activity} <- insert(data, local), {:ok, activity} <- insert(data, local),
# Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
{:ok, _actor} <- User.decrease_note_count(user), {:ok, _actor} <- decrease_note_count_if_public(user, object),
:ok <- maybe_federate(activity) do :ok <- maybe_federate(activity) do
{:ok, activity} {:ok, activity}
end end
@ -420,6 +425,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
@valid_visibilities ~w[direct unlisted public private] @valid_visibilities ~w[direct unlisted public private]
defp restrict_visibility(query, %{visibility: visibility})
when is_list(visibility) do
if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
query =
from(
a in query,
where:
fragment(
"activity_visibility(?, ?, ?) = ANY (?)",
a.actor,
a.recipients,
a.data,
^visibility
)
)
Ecto.Adapters.SQL.to_sql(:all, Repo, query)
query
else
Logger.error("Could not restrict visibility to #{visibility}")
end
end
defp restrict_visibility(query, %{visibility: visibility}) defp restrict_visibility(query, %{visibility: visibility})
when visibility in @valid_visibilities do when visibility in @valid_visibilities do
query = query =

View file

@ -23,15 +23,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
defp score_displayname(_), do: 0.0 defp score_displayname(_), do: 0.0
defp determine_if_followbot(%User{nickname: nickname, name: displayname}) do defp determine_if_followbot(%User{nickname: nickname, name: displayname}) do
# nickname will always be a binary string because it's generated by Pleroma.
nick_score = nick_score =
nickname nickname
|> String.downcase() |> String.downcase()
|> score_nickname() |> score_nickname()
# displayname will either be a binary string or nil, if a displayname isn't set.
name_score = name_score =
displayname if is_binary(displayname) do
|> String.downcase() displayname
|> score_displayname() |> String.downcase()
|> score_displayname()
else
0.0
end
nick_score + name_score nick_score + name_score
end end

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Pleroma.Web alias Pleroma.Web
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.User alias Pleroma.User
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Web.Router.Helpers alias Pleroma.Web.Router.Helpers
@ -274,13 +275,31 @@ defmodule Pleroma.Web.ActivityPub.Utils do
Repo.all(query) Repo.all(query)
end end
def make_like_data(%User{ap_id: ap_id} = actor, %{data: %{"id" => id}} = object, activity_id) do def make_like_data(
%User{ap_id: ap_id} = actor,
%{data: %{"actor" => object_actor_id, "id" => id}} = object,
activity_id
) do
object_actor = User.get_cached_by_ap_id(object_actor_id)
to =
if Visibility.is_public?(object) do
[actor.follower_address, object.data["actor"]]
else
[object.data["actor"]]
end
cc =
(object.data["to"] ++ (object.data["cc"] || []))
|> List.delete(actor.ap_id)
|> List.delete(object_actor.follower_address)
data = %{ data = %{
"type" => "Like", "type" => "Like",
"actor" => ap_id, "actor" => ap_id,
"object" => id, "object" => id,
"to" => [actor.follower_address, object.data["actor"]], "to" => to,
"cc" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => cc,
"context" => object.data["context"] "context" => object.data["context"]
} }

View file

@ -3,10 +3,12 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.AdminAPIController do defmodule Pleroma.Web.AdminAPI.AdminAPIController do
@users_page_size 50
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.TwitterAPI.UserView alias Pleroma.Web.MastodonAPI.Admin.AccountView
import Pleroma.Web.ControllerHelper, only: [json_response: 3] import Pleroma.Web.ControllerHelper, only: [json_response: 3]
@ -48,7 +50,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
{:ok, updated_user} = User.deactivate(user, !user.info.deactivated) {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
conn conn
|> json(UserView.render("show_for_admin.json", %{user: updated_user})) |> json(AccountView.render("show.json", %{user: updated_user}))
end end
def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
@ -61,11 +63,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
do: json_response(conn, :no_content, "") do: json_response(conn, :no_content, "")
end end
def list_users(%{assigns: %{user: admin}} = conn, _data) do def list_users(%{assigns: %{user: admin}} = conn, params) do
users = User.all_except_one(admin) {page, page_size} = page_params(params)
conn with {:ok, users, count} <-
|> json(UserView.render("index_for_admin.json", %{users: users})) User.search_for_admin(%{
query: params["query"],
admin: admin,
local: params["local_only"] == "true",
page: page,
page_size: page_size
}),
do:
conn
|> json(
AccountView.render("index.json",
users: users,
count: count,
page_size: page_size
)
)
end end
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname}) def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
@ -211,4 +228,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> put_status(500) |> put_status(500)
|> json("Something went wrong") |> json("Something went wrong")
end end
defp page_params(params) do
{get_page(params["page"]), get_page_size(params["page_size"])}
end
defp get_page(page_string) when is_nil(page_string), do: 1
defp get_page(page_string) do
case Integer.parse(page_string) do
{page, _} -> page
:error -> 1
end
end
defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
defp get_page_size(page_size_string) do
case Integer.parse(page_size_string) do
{page_size, _} -> page_size
:error -> @users_page_size
end
end
end end

View file

@ -14,6 +14,19 @@ defmodule Pleroma.Web.CommonAPI do
import Pleroma.Web.CommonAPI.Utils import Pleroma.Web.CommonAPI.Utils
def follow(follower, followed) do
with {:ok, follower} <- User.maybe_direct_follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed),
{:ok, follower, followed} <-
User.wait_and_refresh(
Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
follower,
followed
) do
{:ok, follower, followed, activity}
end
end
def delete(activity_id, user) do def delete(activity_id, user) do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id), with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.normalize(object_id), %Object{} = object <- Object.normalize(object_id),

View file

@ -15,14 +15,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web alias Pleroma.Web
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Push
alias Push.Subscription
alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonView alias Pleroma.Web.MastodonAPI.MastodonView
alias Pleroma.Web.MastodonAPI.PushSubscriptionView
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MastodonAPI.ReportView alias Pleroma.Web.MastodonAPI.ReportView
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@ -193,6 +190,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do
params =
conn.params
|> Map.drop(["since_id", "max_id"])
|> Map.merge(params)
last = List.last(activities) last = List.last(activities)
first = List.first(activities) first = List.first(activities)
@ -292,13 +294,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
def dm_timeline(%{assigns: %{user: user}} = conn, params) do def dm_timeline(%{assigns: %{user: user}} = conn, params) do
query = params =
ActivityPub.fetch_activities_query( params
[user.ap_id], |> Map.put("type", "Create")
Map.merge(params, %{"type" => "Create", visibility: "direct"}) |> Map.put("blocking_user", user)
) |> Map.put("user", user)
|> Map.put(:visibility, "direct")
activities = Repo.all(query) activities =
[user.ap_id]
|> ActivityPub.fetch_activities_query(params)
|> Repo.all()
conn conn
|> add_link_headers(:dm_timeline, activities) |> add_link_headers(:dm_timeline, activities)
@ -733,14 +739,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with %User{} = followed <- Repo.get(User, id), with %User{} = followed <- Repo.get(User, id),
{:ok, follower} <- User.maybe_direct_follow(follower, followed), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
{:ok, _activity} <- ActivityPub.follow(follower, followed),
{:ok, follower, followed} <-
User.wait_and_refresh(
Config.get([:activitypub, :follow_handshake_timeout]),
follower,
followed
) do
conn conn
|> put_view(AccountView) |> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed}) |> render("relationship.json", %{user: follower, target: followed})
@ -754,8 +753,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
with %User{} = followed <- Repo.get_by(User, nickname: uri), with %User{} = followed <- Repo.get_by(User, nickname: uri),
{:ok, follower} <- User.maybe_direct_follow(follower, followed), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
conn conn
|> put_view(AccountView) |> put_view(AccountView)
|> render("account.json", %{user: followed, for: follower}) |> render("account.json", %{user: followed, for: follower})
@ -894,7 +892,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true", user) accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
statuses = status_search(user, query) statuses = status_search(user, query)
@ -919,7 +917,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true", user) accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
statuses = status_search(user, query) statuses = status_search(user, query)
@ -941,7 +939,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true", user) accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user)
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user) res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
@ -1424,37 +1422,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{}) json(conn, %{})
end end
def create_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do # fallback action
true = Push.enabled() #
Subscription.delete_if_exists(user, token)
{:ok, subscription} = Subscription.create(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
true = Push.enabled()
subscription = Subscription.get(user, token)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def update_push_subscription(
%{assigns: %{user: user, token: token}} = conn,
params
) do
true = Push.enabled()
{:ok, subscription} = Subscription.update(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
true = Push.enabled()
{:ok, _response} = Subscription.delete(user, token)
json(conn, %{})
end
def errors(conn, _) do def errors(conn, _) do
conn conn
|> put_status(500) |> put_status(500)

View file

@ -0,0 +1,71 @@
# 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.SubscriptionController do
@moduledoc "The module represents functions to manage user subscriptions."
use Pleroma.Web, :controller
alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
action_fallback(:errors)
# Creates PushSubscription
# POST /api/v1/push/subscription
#
def create(%{assigns: %{user: user, token: token}} = conn, params) do
with true <- Push.enabled(),
{:ok, _} <- Subscription.delete_if_exists(user, token),
{:ok, subscription} <- Subscription.create(user, token, params) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end
# Gets PushSubscription
# GET /api/v1/push/subscription
#
def get(%{assigns: %{user: user, token: token}} = conn, _params) do
with true <- Push.enabled(),
{:ok, subscription} <- Subscription.get(user, token) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end
# Updates PushSubscription
# PUT /api/v1/push/subscription
#
def update(%{assigns: %{user: user, token: token}} = conn, params) do
with true <- Push.enabled(),
{:ok, subscription} <- Subscription.update(user, token, params) do
view = View.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
end
# Deletes PushSubscription
# DELETE /api/v1/push/subscription
#
def delete(%{assigns: %{user: user, token: token}} = conn, _params) do
with true <- Push.enabled(),
{:ok, _response} <- Subscription.delete(user, token),
do: json(conn, %{})
end
# fallback action
#
def errors(conn, {:error, :not_found}) do
conn
|> put_status(404)
|> json("Not found")
end
def errors(conn, _) do
conn
|> put_status(500)
|> json("Something went wrong")
end
end

View file

@ -0,0 +1,25 @@
# 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.Admin.AccountView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.Admin.AccountView
def render("index.json", %{users: users, count: count, page_size: page_size}) do
%{
users: render_many(users, AccountView, "show.json", as: :user),
count: count,
page_size: page_size
}
end
def render("show.json", %{user: user}) do
%{
"id" => user.id,
"nickname" => user.nickname,
"deactivated" => user.info.deactivated
}
end
end

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
use Pleroma.Web, :view use Pleroma.Web, :view
alias Pleroma.Web.Push
def render("push_subscription.json", %{subscription: subscription}) do def render("push_subscription.json", %{subscription: subscription}) do
%{ %{
@ -14,7 +15,5 @@ defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
} }
end end
defp server_key do defp server_key, do: Keyword.get(Push.vapid_config(), :public_key)
Keyword.get(Application.get_env(:web_push_encryption, :vapid_details), :public_key)
end
end end

View file

@ -17,14 +17,14 @@ defmodule Pleroma.Web.Metadata.Utils do
|> Formatter.truncate() |> Formatter.truncate()
end end
def scrub_html_and_truncate(content) when is_binary(content) do def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
content content
# html content comes from DB already encoded, decode first and scrub after # html content comes from DB already encoded, decode first and scrub after
|> HtmlEntities.decode() |> HtmlEntities.decode()
|> String.replace(~r/<br\s?\/?>/, " ") |> String.replace(~r/<br\s?\/?>/, " ")
|> HTML.strip_tags() |> HTML.strip_tags()
|> Formatter.demojify() |> Formatter.demojify()
|> Formatter.truncate() |> Formatter.truncate(max_length)
end end
def attachment_url(url) do def attachment_url(url) do

View file

@ -6,7 +6,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.Config alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.Stats alias Pleroma.Stats
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web alias Pleroma.Web
@ -86,8 +85,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
end end
staff_accounts = staff_accounts =
User.moderator_user_query() User.all_superusers()
|> Repo.all()
|> Enum.map(fn u -> u.ap_id end) |> Enum.map(fn u -> u.ap_id end)
mrf_user_allowlist = mrf_user_allowlist =

View file

@ -0,0 +1,127 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.Impl do
@moduledoc "The module represents implementation push web notification"
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.Push.Subscription
alias Pleroma.Web.Metadata.Utils
alias Pleroma.Notification
require Logger
import Ecto.Query
@types ["Create", "Follow", "Announce", "Like"]
@doc "Performs sending notifications for user subscriptions"
@spec perform_send(Notification.t()) :: list(any)
def perform_send(%{activity: %{data: %{"type" => activity_type}}, user_id: user_id} = notif)
when activity_type in @types do
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
type = Activity.mastodon_notification_type(notif.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)
for subscription <- fetch_subsriptions(user_id),
get_in(subscription.data, ["alerts", type]) do
%{
title: format_title(notif),
access_token: subscription.token.token,
body: format_body(notif, actor),
notification_id: notif.id,
notification_type: type,
icon: avatar_url,
preferred_locale: "en"
}
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription)
end
end
def perform_send(_) do
Logger.warn("Unknown notification type")
:error
end
@doc "Push message to web"
def push_message(body, sub, api_key, subscription) do
case WebPushEncryption.send_web_push(body, sub, api_key) do
{:ok, %{status_code: code}} when 400 <= code and code < 500 ->
Logger.debug("Removing subscription record")
Repo.delete!(subscription)
:ok
{:ok, %{status_code: code}} when 200 <= code and code < 300 ->
:ok
{:ok, %{status_code: code}} ->
Logger.error("Web Push Notification failed with code: #{code}")
:error
_ ->
Logger.error("Web Push Notification failed with unknown error")
:error
end
end
@doc "Gets user subscriptions"
def fetch_subsriptions(user_id) do
Subscription
|> where(user_id: ^user_id)
|> preload(:token)
|> Repo.all()
end
def build_sub(subscription) do
%{
keys: %{
p256dh: subscription.key_p256dh,
auth: subscription.key_auth
},
endpoint: subscription.endpoint
}
end
def format_body(
%{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
actor
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => "Announce", "object" => activity_id}}},
actor
) do
%Activity{data: %{"object" => %{"id" => object_id}}} = Activity.get_by_ap_id(activity_id)
%Object{data: %{"content" => content}} = Object.get_by_ap_id(object_id)
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => type}}},
actor
)
when type in ["Follow", "Like"] do
case type do
"Follow" -> "@#{actor.nickname} has followed you"
"Like" -> "@#{actor.nickname} has favorited your post"
end
end
def format_title(%{activity: %{data: %{"type" => type}}}) do
case type do
"Create" -> "New Mention"
"Follow" -> "New Follower"
"Announce" -> "New Repeat"
"Like" -> "New Favorite"
end
end
end

View file

@ -5,14 +5,13 @@
defmodule Pleroma.Web.Push do defmodule Pleroma.Web.Push do
use GenServer use GenServer
alias Pleroma.Repo alias Pleroma.Web.Push.Impl
alias Pleroma.User
alias Pleroma.Web.Push.Subscription
require Logger require Logger
import Ecto.Query
@types ["Create", "Follow", "Announce", "Like"] ##############
# Client API #
##############
def start_link() do def start_link() do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__) GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
@ -30,14 +29,18 @@ defmodule Pleroma.Web.Push do
end end
end end
def send(notification) do def send(notification),
if enabled() do do: GenServer.cast(__MODULE__, {:send, notification})
GenServer.cast(Pleroma.Web.Push, {:send, notification})
end
end
####################
# Server Callbacks #
####################
@impl true
def init(:ok) do def init(:ok) do
if !enabled() do if enabled() do
{:ok, nil}
else
Logger.warn(""" Logger.warn("""
VAPID key pair is not found. If you wish to enabled web push, please run VAPID key pair is not found. If you wish to enabled web push, please run
@ -47,93 +50,15 @@ defmodule Pleroma.Web.Push do
""") """)
:ignore :ignore
else
{:ok, nil}
end end
end end
def handle_cast( @impl true
{:send, %{activity: %{data: %{"type" => type}}, user_id: user_id} = notification}, def handle_cast({:send, notification}, state) do
state if enabled() do
) Impl.perform_send(notification)
when type in @types do end
actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
type = Pleroma.Activity.mastodon_notification_type(notification.activity)
Subscription
|> where(user_id: ^user_id)
|> preload(:token)
|> Repo.all()
|> Enum.filter(fn subscription ->
get_in(subscription.data, ["alerts", type]) || false
end)
|> Enum.each(fn subscription ->
sub = %{
keys: %{
p256dh: subscription.key_p256dh,
auth: subscription.key_auth
},
endpoint: subscription.endpoint
}
body =
Jason.encode!(%{
title: format_title(notification),
access_token: subscription.token.token,
body: format_body(notification, actor),
notification_id: notification.id,
notification_type: type,
icon: User.avatar_url(actor),
preferred_locale: "en"
})
case WebPushEncryption.send_web_push(
body,
sub,
Application.get_env(:web_push_encryption, :gcm_api_key)
) do
{:ok, %{status_code: code}} when 400 <= code and code < 500 ->
Logger.debug("Removing subscription record")
Repo.delete!(subscription)
:ok
{:ok, %{status_code: code}} when 200 <= code and code < 300 ->
:ok
{:ok, %{status_code: code}} ->
Logger.error("Web Push Notification failed with code: #{code}")
:error
_ ->
Logger.error("Web Push Notification failed with unknown error")
:error
end
end)
{:noreply, state} {:noreply, state}
end end
def handle_cast({:send, _}, state) do
Logger.warn("Unknown notification type")
{:noreply, state}
end
defp format_title(%{activity: %{data: %{"type" => type}}}) do
case type do
"Create" -> "New Mention"
"Follow" -> "New Follower"
"Announce" -> "New Repeat"
"Like" -> "New Favorite"
end
end
defp format_body(%{activity: %{data: %{"type" => type}}}, actor) do
case type do
"Create" -> "@#{actor.nickname} has mentioned you"
"Follow" -> "@#{actor.nickname} has followed you"
"Announce" -> "@#{actor.nickname} has repeated your post"
"Like" -> "@#{actor.nickname} has favorited your post"
end
end
end end

View file

@ -12,6 +12,8 @@ defmodule Pleroma.Web.Push.Subscription do
alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Push.Subscription alias Pleroma.Web.Push.Subscription
@type t :: %__MODULE__{}
schema "push_subscriptions" do schema "push_subscriptions" do
belongs_to(:user, User, type: Pleroma.FlakeId) belongs_to(:user, User, type: Pleroma.FlakeId)
belongs_to(:token, Token) belongs_to(:token, Token)
@ -50,24 +52,32 @@ defmodule Pleroma.Web.Push.Subscription do
}) })
end end
@doc "Gets subsciption by user & token"
@spec get(User.t(), Token.t()) :: {:ok, t()} | {:error, :not_found}
def get(%User{id: user_id}, %Token{id: token_id}) do def get(%User{id: user_id}, %Token{id: token_id}) do
Repo.get_by(Subscription, user_id: user_id, token_id: token_id) case Repo.get_by(Subscription, user_id: user_id, token_id: token_id) do
nil -> {:error, :not_found}
subscription -> {:ok, subscription}
end
end end
def update(user, token, params) do def update(user, token, params) do
get(user, token) with {:ok, subscription} <- get(user, token) do
|> change(data: alerts(params)) subscription
|> Repo.update() |> change(data: alerts(params))
|> Repo.update()
end
end end
def delete(user, token) do def delete(user, token) do
Repo.delete(get(user, token)) with {:ok, subscription} <- get(user, token),
do: Repo.delete(subscription)
end end
def delete_if_exists(user, token) do def delete_if_exists(user, token) do
case get(user, token) do case get(user, token) do
nil -> {:ok, nil} {:error, _} -> {:ok, nil}
sub -> Repo.delete(sub) {:ok, sub} -> Repo.delete(sub)
end end
end end

52
lib/pleroma/web/rel_me.ex Normal file
View file

@ -0,0 +1,52 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RelMe do
@hackney_options [
pool: :media,
timeout: 2_000,
recv_timeout: 2_000,
max_body: 2_000_000
]
if Mix.env() == :test do
def parse(url) when is_binary(url), do: parse_url(url)
else
def parse(url) when is_binary(url) do
Cachex.fetch!(:rel_me_cache, url, fn _ ->
{:commit, parse_url(url)}
end)
rescue
e -> {:error, "Cachex error: #{inspect(e)}"}
end
end
def parse(_), do: {:error, "No URL provided"}
defp parse_url(url) do
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
data =
Floki.attribute(html, "link[rel~=me]", "href") ++
Floki.attribute(html, "a[rel~=me]", "href")
{:ok, data}
rescue
e -> {:error, "Parsing error: #{inspect(e)}"}
end
def maybe_put_rel_me("http" <> _ = target_page, profile_urls) when is_list(profile_urls) do
{:ok, rel_me_hrefs} = parse(target_page)
true = Enum.any?(rel_me_hrefs, fn x -> x in profile_urls end)
"me"
rescue
_ -> nil
end
def maybe_put_rel_me(_, _) do
nil
end
end

View file

@ -8,10 +8,24 @@ defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.HTML alias Pleroma.HTML
alias Pleroma.Web.RichMedia.Parser alias Pleroma.Web.RichMedia.Parser
defp validate_page_url(page_url) when is_binary(page_url) do
if AutoLinker.Parser.is_url?(page_url, true) do
URI.parse(page_url) |> validate_page_url
else
:error
end
end
defp validate_page_url(%URI{authority: nil}), do: :error
defp validate_page_url(%URI{scheme: nil}), do: :error
defp validate_page_url(%URI{}), do: :ok
defp validate_page_url(_), do: :error
def fetch_data_for_activity(%Activity{} = activity) do def fetch_data_for_activity(%Activity{} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]), with true <- Pleroma.Config.get([:rich_media, :enabled]),
%Object{} = object <- Object.normalize(activity.data["object"]), %Object{} = object <- Object.normalize(activity.data["object"]),
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]), {:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
:ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do {:ok, rich_media} <- Parser.parse(page_url) do
%{page_url: page_url, rich_media: rich_media} %{page_url: page_url, rich_media: rich_media}
else else

View file

@ -303,10 +303,10 @@ defmodule Pleroma.Web.Router do
scope [] do scope [] do
pipe_through(:oauth_push) pipe_through(:oauth_push)
post("/push/subscription", MastodonAPIController, :create_push_subscription) post("/push/subscription", SubscriptionController, :create)
get("/push/subscription", MastodonAPIController, :get_push_subscription) get("/push/subscription", SubscriptionController, :get)
put("/push/subscription", MastodonAPIController, :update_push_subscription) put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", MastodonAPIController, :delete_push_subscription) delete("/push/subscription", SubscriptionController, :delete)
end end
end end

View file

@ -197,10 +197,12 @@ defmodule Pleroma.Web.Streamer do
if socket.assigns[:user] do if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || [] blocks = user.info.blocks || []
mutes = user.info.mutes || []
parent = Object.normalize(item.data["object"]) parent = Object.normalize(item.data["object"])
unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
parent.data["actor"] in blocks or parent.data["actor"] in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)}) send(socket.transport_pid, {:text, represent_update(item, user)})
end end
else else
@ -224,8 +226,9 @@ defmodule Pleroma.Web.Streamer do
if socket.assigns[:user] do if socket.assigns[:user] do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || [] blocks = user.info.blocks || []
mutes = user.info.mutes || []
unless item.actor in blocks do unless item.actor in blocks or item.actor in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)}) send(socket.transport_pid, {:text, represent_update(item, user)})
end end
else else

View file

@ -28,18 +28,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end end
def follow(%User{} = follower, params) do def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params), with {:ok, %User{} = followed} <- get_user(params) do
{:ok, follower} <- User.maybe_direct_follow(follower, followed), CommonAPI.follow(follower, followed)
{:ok, activity} <- ActivityPub.follow(follower, followed),
{:ok, follower, followed} <-
User.wait_and_refresh(
Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
follower,
followed
) do
{:ok, follower, followed, activity}
else
err -> err
end end
end end

View file

@ -167,6 +167,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
params params
|> Map.put("type", ["Create", "Announce", "Follow", "Like"]) |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
|> Map.put("blocking_user", user) |> Map.put("blocking_user", user)
|> Map.put(:visibility, ~w[unlisted public private])
activities = ActivityPub.fetch_activities([user.ap_id], params) activities = ActivityPub.fetch_activities([user.ap_id], params)
@ -176,13 +177,16 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end end
def dm_timeline(%{assigns: %{user: user}} = conn, params) do def dm_timeline(%{assigns: %{user: user}} = conn, params) do
query = params =
ActivityPub.fetch_activities_query( params
[user.ap_id], |> Map.put("type", "Create")
Map.merge(params, %{"type" => "Create", "user" => user, visibility: "direct"}) |> Map.put("blocking_user", user)
) |> Map.put("user", user)
|> Map.put(:visibility, "direct")
activities = Repo.all(query) activities =
ActivityPub.fetch_activities_query([user.ap_id], params)
|> Repo.all()
conn conn
|> put_view(ActivityView) |> put_view(ActivityView)
@ -702,7 +706,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end end
def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do
users = User.search(query, true, user) users = User.search(query, resolve: true, for_user: user)
conn conn
|> put_view(UserView) |> put_view(UserView)

View file

@ -9,7 +9,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Pleroma.Web.TwitterAPI.UserView
def render("show.json", %{user: user = %User{}} = assigns) do def render("show.json", %{user: user = %User{}} = assigns) do
render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns) render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns)
@ -27,19 +26,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
else: %{} else: %{}
end end
def render("index_for_admin.json", %{users: users} = opts) do
users
|> render_many(UserView, "show_for_admin.json", opts)
end
def render("show_for_admin.json", %{user: user}) do
%{
"id" => user.id,
"nickname" => user.nickname,
"deactivated" => user.info.deactivated
}
end
def render("short.json", %{ def render("short.json", %{
user: %User{ user: %User{
nickname: nickname, nickname: nickname,
@ -133,7 +119,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
"tags" => user.tags "tags" => user.tags
} }
|> maybe_with_activation_status(user, for_user) |> maybe_with_activation_status(user, for_user)
|> maybe_with_follow_request_count(user, for_user)
} }
data = data =
@ -155,14 +140,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
defp maybe_with_activation_status(data, _, _), do: data defp maybe_with_activation_status(data, _, _), do: data
defp maybe_with_follow_request_count(data, %User{id: id, info: %{locked: true}} = user, %User{
id: id
}) do
Map.put(data, "follow_request_count", user.info.follow_request_count)
end
defp maybe_with_follow_request_count(data, _, _), do: data
defp maybe_with_role(data, %User{id: id} = user, %User{id: id}) do defp maybe_with_role(data, %User{id: id} = user, %User{id: id}) do
Map.merge(data, %{"role" => role(user), "show_role" => user.info.show_role}) Map.merge(data, %{"role" => role(user), "show_role" => user.info.show_role})
end end

View file

@ -76,7 +76,7 @@ defmodule Pleroma.Mixfile do
{:ex_aws, "~> 2.0"}, {:ex_aws, "~> 2.0"},
{:ex_aws_s3, "~> 2.0"}, {:ex_aws_s3, "~> 2.0"},
{:earmark, "~> 1.3"}, {:earmark, "~> 1.3"},
{:ex_machina, "~> 2.2", only: :test}, {:ex_machina, "~> 2.3", only: :test},
{:credo, "~> 0.9.3", only: [:dev, :test]}, {:credo, "~> 0.9.3", only: [:dev, :test]},
{:mock, "~> 0.3.1", only: :test}, {:mock, "~> 0.3.1", only: :test},
{:crypt, {:crypt,

View file

@ -14,14 +14,14 @@
"credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm"}, "decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.10", "e7366dc82f48f8dd78fcbf3ab50985ceeb11cb3dc93435147c6e13f2cda0992e", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"},
"ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"}, "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
"ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
"ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]},
"floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"gen_smtp": {:hex, :gen_smtp, "0.13.0", "11f08504c4bdd831dc520b8f84a1dce5ce624474a797394e7aafd3c29f5dcd25", [:rebar3], [], "hexpm"}, "gen_smtp": {:hex, :gen_smtp, "0.13.0", "11f08504c4bdd831dc520b8f84a1dce5ce624474a797394e7aafd3c29f5dcd25", [:rebar3], [], "hexpm"},
@ -53,7 +53,7 @@
"plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},

View file

@ -0,0 +1,41 @@
defmodule Pleroma.Repo.Migrations.UpdateUserNoteCounters do
use Ecto.Migration
@public "https://www.w3.org/ns/activitystreams#Public"
def up do
execute """
WITH public_note_count AS (
SELECT
data->>'actor' AS actor,
count(id) AS count
FROM objects
WHERE data->>'type' = 'Note' AND (
data->'cc' ? '#{@public}' OR data->'to' ? '#{@public}'
)
GROUP BY data->>'actor'
)
UPDATE users AS u
SET "info" = jsonb_set(u.info, '{note_count}', o.count::varchar::jsonb, true)
FROM public_note_count AS o
WHERE u.ap_id = o.actor
"""
end
def down do
execute """
WITH public_note_count AS (
SELECT
data->>'actor' AS actor,
count(id) AS count
FROM objects
WHERE data->>'type' = 'Note'
GROUP BY data->>'actor'
)
UPDATE users AS u
SET "info" = jsonb_set(u.info, '{note_count}', o.count::varchar::jsonb, true)
FROM public_note_count AS o
WHERE u.ap_id = o.actor
"""
end
end

View file

@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.f8cd72107c472bb05fac426b53ec499b.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.7bce4ebd4510d2c5e6d8.js></script><script type=text/javascript src=/static/js/vendor.2a9228e5bcaf054e8060.js></script><script type=text/javascript src=/static/js/app.2a6f16b7ee4b2642dacc.js></script></body></html> <!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.6da3b5e56eb2330b1b175cca622a3d42.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.6c8fd5aa8c8c4aee99d3.js></script><script type=text/javascript src=/static/js/vendor.360be732615100da981f.js></script><script type=text/javascript src=/static/js/app.36ed651e315106252e56.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var r=window.webpackJsonp;window.webpackJsonp=function(o,p){for(var c,l,s=0,i=[];s<o.length;s++)l=o[s],a[l]&&i.push.apply(i,a[l]),a[l]=0;for(c in p)Object.prototype.hasOwnProperty.call(p,c)&&(e[c]=p[c]);for(r&&r(o,p);i.length;)i.shift().call(null,t);if(p[0])return n[0]=0,t(0)};var n={},a={0:0};t.e=function(e,r){if(0===a[e])return r.call(null,t);if(void 0!==a[e])a[e].push(r);else{a[e]=[r];var n=document.getElementsByTagName("head")[0],o=document.createElement("script");o.type="text/javascript",o.charset="utf-8",o.async=!0,o.src=t.p+"static/js/"+e+"."+{1:"360be732615100da981f",2:"36ed651e315106252e56"}[e]+".js",n.appendChild(o)}},t.m=e,t.c=n,t.p="/"}([]);
//# sourceMappingURL=manifest.6c8fd5aa8c8c4aee99d3.js.map

View file

@ -1,2 +0,0 @@
!function(e){function t(a){if(r[a])return r[a].exports;var n=r[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var a=window.webpackJsonp;window.webpackJsonp=function(c,o){for(var p,l,s=0,i=[];s<c.length;s++)l=c[s],n[l]&&i.push.apply(i,n[l]),n[l]=0;for(p in o)Object.prototype.hasOwnProperty.call(o,p)&&(e[p]=o[p]);for(a&&a(c,o);i.length;)i.shift().call(null,t);if(o[0])return r[0]=0,t(0)};var r={},n={0:0};t.e=function(e,a){if(0===n[e])return a.call(null,t);if(void 0!==n[e])n[e].push(a);else{n[e]=[a];var r=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.src=t.p+"static/js/"+e+"."+{1:"2a9228e5bcaf054e8060",2:"2a6f16b7ee4b2642dacc"}[e]+".js",r.appendChild(c)}},t.m=e,t.c=r,t.p="/"}([]);
//# sourceMappingURL=manifest.7bce4ebd4510d2c5e6d8.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
[
"teď",
["%s s", "%s s"],
["%s min", "%s min"],
["%s h", "%s h"],
["%s d", "%s d"],
["%s týd", "%s týd"],
["%s měs", "%s měs"],
["%s r", "%s l"]
]

View file

@ -1,4 +1,4 @@
var serviceWorkerOption = {"assets":["/static/img/nsfw.74818f9.png","/static/js/manifest.7bce4ebd4510d2c5e6d8.js","/static/js/vendor.2a9228e5bcaf054e8060.js","/static/js/app.2a6f16b7ee4b2642dacc.js","/static/css/app.f8cd72107c472bb05fac426b53ec499b.css"]}; var serviceWorkerOption = {"assets":["/static/img/nsfw.74818f9.png","/static/js/manifest.6c8fd5aa8c8c4aee99d3.js","/static/js/vendor.360be732615100da981f.js","/static/js/app.36ed651e315106252e56.js","/static/css/app.6da3b5e56eb2330b1b175cca622a3d42.css"]};
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var t={};return n.m=e,n.c=t,n.p="/",n(0)}([function(e,n,t){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(){return u.default.getItem("vuex-lz").then(function(e){return e.config.webPushNotifications})}function i(){return clients.matchAll({includeUncontrolled:!0}).then(function(e){return e.filter(function(e){var n=e.type;return"window"===n})})}var a=t(1),u=r(a);self.addEventListener("push",function(e){e.data&&e.waitUntil(o().then(function(n){return n&&i().then(function(n){var t=e.data.json();if(0===n.length)return self.registration.showNotification(t.title,t)})}))}),self.addEventListener("notificationclick",function(e){e.notification.close(),e.waitUntil(i().then(function(e){for(var n=0;n<e.length;n++){var t=e[n];if("/"===t.url&&"focus"in t)return t.focus()}if(clients.openWindow)return clients.openWindow("/")}))})},function(e,n){/*! !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var t={};return n.m=e,n.c=t,n.p="/",n(0)}([function(e,n,t){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(){return u.default.getItem("vuex-lz").then(function(e){return e.config.webPushNotifications})}function i(){return clients.matchAll({includeUncontrolled:!0}).then(function(e){return e.filter(function(e){var n=e.type;return"window"===n})})}var a=t(1),u=r(a);self.addEventListener("push",function(e){e.data&&e.waitUntil(o().then(function(n){return n&&i().then(function(n){var t=e.data.json();if(0===n.length)return self.registration.showNotification(t.title,t)})}))}),self.addEventListener("notificationclick",function(e){e.notification.close(),e.waitUntil(i().then(function(e){for(var n=0;n<e.length;n++){var t=e[n];if("/"===t.url&&"focus"in t)return t.focus()}if(clients.openWindow)return clients.openWindow("/")}))})},function(e,n){/*!
localForage -- Offline Storage, Improved localForage -- Offline Storage, Improved

14
test/fixtures/rel_me_anchor.html vendored Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Blog</title>
</head>
<body>
<article>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit ameph, …</p>
<a rel="me" href="https://social.example.org/users/lain">lains account</a>
</article>
</body>
</html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Blog</title>
</head>
<body>
<article>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit ameph, …</p>
<a rel="me nofollow" href="https://social.example.org/users/lain">lains account</a>
</article>
</body>
</html>

14
test/fixtures/rel_me_link.html vendored Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Blog</title>
<link rel="me" href="https://social.example.org/users/lain"/>
</head>
<body>
<article>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit ameph, …</p>
</article>
</body>
</html>

14
test/fixtures/rel_me_null.html vendored Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Blog</title>
</head>
<body>
<article>
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit ameph, …</p>
<a rel="nofollow" href="https://social.example.org/users/lain">lains account</a>
</article>
</body>
</html>

View file

@ -23,7 +23,7 @@ defmodule Pleroma.Factory do
} }
end end
def note_factory do def note_factory(attrs \\ %{}) do
text = sequence(:text, &"This is :moominmamma: note #{&1}") text = sequence(:text, &"This is :moominmamma: note #{&1}")
user = insert(:user) user = insert(:user)
@ -46,7 +46,7 @@ defmodule Pleroma.Factory do
} }
%Pleroma.Object{ %Pleroma.Object{
data: data data: merge_attributes(data, Map.get(attrs, :data, %{}))
} }
end end
@ -95,8 +95,8 @@ defmodule Pleroma.Factory do
} }
end end
def note_activity_factory do def note_activity_factory(attrs \\ %{}) do
note = insert(:note) note = attrs[:note] || insert(:note)
data = %{ data = %{
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
@ -135,9 +135,9 @@ defmodule Pleroma.Factory do
} }
end end
def announce_activity_factory do def announce_activity_factory(attrs \\ %{}) do
note_activity = insert(:note_activity) note_activity = attrs[:note_activity] || insert(:note_activity)
user = insert(:user) user = attrs[:user] || insert(:user)
data = %{ data = %{
"type" => "Announce", "type" => "Announce",
@ -229,15 +229,32 @@ defmodule Pleroma.Factory do
end end
def oauth_token_factory do def oauth_token_factory do
user = insert(:user)
oauth_app = insert(:oauth_app) oauth_app = insert(:oauth_app)
%Pleroma.Web.OAuth.Token{ %Pleroma.Web.OAuth.Token{
token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(), token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(), refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
user_id: user.id, user: build(:user),
app_id: oauth_app.id, app_id: oauth_app.id,
valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10) valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)
} }
end end
def push_subscription_factory do
%Pleroma.Web.Push.Subscription{
user: build(:user),
token: build(:oauth_token),
endpoint: "https://example.com/example/1234",
key_auth: "8eDyX_uCN0XRhSbY5hs7Hg==",
key_p256dh:
"BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA=",
data: %{}
}
end
def notification_factory do
%Pleroma.Notification{
user: build(:user)
}
end
end end

View file

@ -0,0 +1,23 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebPushHttpClientMock do
def get(url, headers \\ [], options \\ []) do
{
res,
%Tesla.Env{status: status}
} = Pleroma.HTTP.request(:get, url, "", headers, options)
{res, %{status_code: status}}
end
def post(url, body, headers \\ [], options \\ []) do
{
res,
%Tesla.Env{status: status}
} = Pleroma.HTTP.request(:post, url, body, headers, options)
{res, %{status_code: status}}
end
end

View file

@ -153,19 +153,20 @@ defmodule Pleroma.UploadTest do
assert Path.basename(attachment_url["href"]) == "an%E2%80%A6%20image.jpg" assert Path.basename(attachment_url["href"]) == "an%E2%80%A6%20image.jpg"
end end
test "replaces : (colon) and ? (question-mark) to %3A and %3F (respectively)" do test "escapes reserved uri characters" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "is:an?image.jpg" filename: ":?#[]@!$&\\'()*+,;=.jpg"
} }
{:ok, data} = Upload.store(file) {:ok, data} = Upload.store(file)
[attachment_url | _] = data["url"] [attachment_url | _] = data["url"]
assert Path.basename(attachment_url["href"]) == "is%3Aan%3Fimage.jpg" assert Path.basename(attachment_url["href"]) ==
"%3A%3F%23%5B%5D%40%21%24%26%5C%27%28%29%2A%2B%2C%3B%3D.jpg"
end end
end end
end end

View file

@ -64,6 +64,20 @@ defmodule Pleroma.UserTest do
assert activity assert activity
end end
test "doesn't return already accepted or duplicate follow requests" do
locked = insert(:user, %{info: %{locked: true}})
pending_follower = insert(:user)
accepted_follower = insert(:user)
Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
Pleroma.Web.TwitterAPI.TwitterAPI.follow(accepted_follower, %{"user_id" => locked.id})
User.maybe_follow(accepted_follower, locked)
assert {:ok, [activity]} = User.get_follow_requests(locked)
assert activity
end
test "follow_all follows mutliple users" do test "follow_all follows mutliple users" do
user = insert(:user) user = insert(:user)
followed_zero = insert(:user) followed_zero = insert(:user)
@ -915,7 +929,8 @@ defmodule Pleroma.UserTest do
{:ok, follower} = User.follow(follower, u1) {:ok, follower} = User.follow(follower, u1)
{:ok, u1} = User.follow(u1, friend) {:ok, u1} = User.follow(u1, friend)
assert [friend.id, follower.id, u2.id] == Enum.map(User.search("doe", false, u1), & &1.id) assert [friend.id, follower.id, u2.id] --
Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == []
end end
test "finds a user whose name is nil" do test "finds a user whose name is nil" do
@ -937,7 +952,7 @@ defmodule Pleroma.UserTest do
end end
test "works with URIs" do test "works with URIs" do
results = User.search("http://mastodon.example.org/users/admin", true) results = User.search("http://mastodon.example.org/users/admin", resolve: true)
result = results |> List.first() result = results |> List.first()
user = User.get_by_ap_id("http://mastodon.example.org/users/admin") user = User.get_by_ap_id("http://mastodon.example.org/users/admin")
@ -1039,6 +1054,22 @@ defmodule Pleroma.UserTest do
assert expected_text == User.parse_bio(bio, user) assert expected_text == User.parse_bio(bio, user)
end end
test "Adds rel=me on linkbacked urls" do
user = insert(:user, ap_id: "http://social.example.org/users/lain")
bio = "http://example.org/rel_me/null"
expected_text = "<a href=\"#{bio}\">#{bio}</a>"
assert expected_text == User.parse_bio(bio, user)
bio = "http://example.org/rel_me/link"
expected_text = "<a href=\"#{bio}\">#{bio}</a>"
assert expected_text == User.parse_bio(bio, user)
bio = "http://example.org/rel_me/anchor"
expected_text = "<a href=\"#{bio}\">#{bio}</a>"
assert expected_text == User.parse_bio(bio, user)
end
end end
test "bookmarks" do test "bookmarks" do

View file

@ -55,6 +55,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id}) ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
assert activities == [public_activity] assert activities == [public_activity]
activities =
ActivityPub.fetch_activities([], %{
:visibility => ~w[private public],
"actor_id" => user.ap_id
})
assert activities == [public_activity, private_activity]
end end
end end
@ -205,6 +213,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity.actor == user.ap_id assert activity.actor == user.ap_id
assert activity.recipients == ["user1", "user2", user.ap_id] assert activity.recipients == ["user1", "user2", user.ap_id]
end end
test "increases user note count only for public activities" do
user = insert(:user)
{:ok, _} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"})
{:ok, _} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"})
{:ok, _} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"})
{:ok, _} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"})
user = Repo.get(User, user.id)
assert user.info.note_count == 2
end
end end
describe "fetch activities for recipients" do describe "fetch activities for recipients" do
@ -640,6 +667,51 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Repo.get(Object, object.id).data["type"] == "Tombstone" assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end end
test "decrements user note count only for public activities" do
user = insert(:user, info: %{note_count: 10})
{:ok, a1} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"})
{:ok, a2} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"})
{:ok, a3} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"})
{:ok, a4} =
CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "direct"})
{:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
user = Repo.get(User, user.id)
assert user.info.note_count == 10
end
test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
user = insert(:user)
note = insert(:note_activity)
{:ok, object} =
Object.get_by_ap_id(note.data["object"]["id"])
|> Object.change(%{
data: %{
"actor" => note.data["object"]["actor"],
"id" => note.data["object"]["id"],
"to" => [user.ap_id],
"type" => "Note"
}
})
|> Object.update_and_set_cache()
{:ok, delete} = ActivityPub.delete(object)
assert user.ap_id in delete.data["to"]
end
end end
describe "timeline post-processing" do describe "timeline post-processing" do

View file

@ -54,4 +54,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
{:ok, _} = AntiFollowbotPolicy.filter(message) {:ok, _} = AntiFollowbotPolicy.filter(message)
end end
test "it gracefully handles nil display names" do
actor = insert(:user, %{name: nil})
target = insert(:user)
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Follow",
"actor" => actor.ap_id,
"object" => target.ap_id,
"id" => "https://example.com/activities/1234"
}
{:ok, _} = AntiFollowbotPolicy.filter(message)
end
end end

View file

@ -1,7 +1,10 @@
defmodule Pleroma.Web.ActivityPub.UtilsTest do defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
import Pleroma.Factory
describe "determine_explicit_mentions()" do describe "determine_explicit_mentions()" do
test "works with an object that has mentions" do test "works with an object that has mentions" do
object = %{ object = %{
@ -54,4 +57,51 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
assert Utils.determine_explicit_mentions(object) == [] assert Utils.determine_explicit_mentions(object) == []
end end
end end
describe "make_like_data" do
setup do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
[user: user, other_user: other_user, third_user: third_user]
end
test "addresses actor's follower address if the activity is public", %{
user: user,
other_user: other_user,
third_user: third_user
} do
expected_to = Enum.sort([user.ap_id, other_user.follower_address])
expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
{:ok, activity} =
CommonAPI.post(user, %{
"status" =>
"hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
})
%{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
assert Enum.sort(to) == expected_to
assert Enum.sort(cc) == expected_cc
end
test "does not adress actor's follower address if the activity is not public", %{
user: user,
other_user: other_user,
third_user: third_user
} do
expected_to = Enum.sort([user.ap_id])
expected_cc = [third_user.ap_id]
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
"visibility" => "private"
})
%{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
assert Enum.sort(to) == expected_to
assert Enum.sort(cc) == expected_cc
end
end
end end

View file

@ -331,22 +331,164 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert conn.status == 200 assert conn.status == 200
end end
test "GET /api/pleroma/admin/users" do describe "GET /api/pleroma/admin/users" do
admin = insert(:user, info: %{is_admin: true}) test "renders users array for the first page" do
user = insert(:user) admin = insert(:user, info: %{is_admin: true})
user = insert(:user)
conn = conn =
build_conn() build_conn()
|> assign(:user, admin) |> assign(:user, admin)
|> get("/api/pleroma/admin/users") |> get("/api/pleroma/admin/users?page=1")
assert json_response(conn, 200) == [ assert json_response(conn, 200) == %{
%{ "count" => 2,
"deactivated" => user.info.deactivated, "page_size" => 50,
"id" => user.id, "users" => [
"nickname" => user.nickname %{
"deactivated" => admin.info.deactivated,
"id" => admin.id,
"nickname" => admin.nickname
},
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
"nickname" => user.nickname
}
]
} }
] end
test "renders empty array for the second page" do
admin = insert(:user, info: %{is_admin: true})
insert(:user)
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?page=2")
assert json_response(conn, 200) == %{
"count" => 2,
"page_size" => 50,
"users" => []
}
end
test "regular search" do
admin = insert(:user, info: %{is_admin: true})
user = insert(:user, nickname: "bob")
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?query=bo")
assert json_response(conn, 200) == %{
"count" => 1,
"page_size" => 50,
"users" => [
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
"nickname" => user.nickname
}
]
}
end
test "regular search with page size" do
admin = insert(:user, info: %{is_admin: true})
user = insert(:user, nickname: "bob")
user2 = insert(:user, nickname: "bo")
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?query=bo&page_size=1&page=1")
assert json_response(conn, 200) == %{
"count" => 2,
"page_size" => 1,
"users" => [
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
"nickname" => user.nickname
}
]
}
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?query=bo&page_size=1&page=2")
assert json_response(conn, 200) == %{
"count" => 2,
"page_size" => 1,
"users" => [
%{
"deactivated" => user2.info.deactivated,
"id" => user2.id,
"nickname" => user2.nickname
}
]
}
end
test "only local users" do
admin = insert(:user, info: %{is_admin: true}, nickname: "john")
user = insert(:user, nickname: "bob")
insert(:user, nickname: "bobb", local: false)
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?query=bo&local_only=true")
assert json_response(conn, 200) == %{
"count" => 1,
"page_size" => 50,
"users" => [
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
"nickname" => user.nickname
}
]
}
end
test "only local users with no query" do
admin = insert(:user, info: %{is_admin: true}, nickname: "john")
user = insert(:user, nickname: "bob")
insert(:user, nickname: "bobb", local: false)
conn =
build_conn()
|> assign(:user, admin)
|> get("/api/pleroma/admin/users?local_only=true")
assert json_response(conn, 200) == %{
"count" => 2,
"page_size" => 50,
"users" => [
%{
"deactivated" => admin.info.deactivated,
"id" => admin.id,
"nickname" => admin.nickname
},
%{
"deactivated" => user.info.deactivated,
"id" => user.id,
"nickname" => user.nickname
}
]
}
end
end end
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do

View file

@ -248,6 +248,33 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert status["url"] != direct.data["id"] assert status["url"] != direct.data["id"]
end end
test "doesn't include DMs from blocked users", %{conn: conn} do
blocker = insert(:user)
blocked = insert(:user)
user = insert(:user)
{:ok, blocker} = User.block(blocker, blocked)
{:ok, _blocked_direct} =
CommonAPI.post(blocked, %{
"status" => "Hi @#{blocker.nickname}!",
"visibility" => "direct"
})
{:ok, direct} =
CommonAPI.post(user, %{
"status" => "Hi @#{blocker.nickname}!",
"visibility" => "direct"
})
res_conn =
conn
|> assign(:user, user)
|> get("api/v1/timelines/direct")
[status] = json_response(res_conn, 200)
assert status["id"] == direct.id
end
test "replying to a status", %{conn: conn} do test "replying to a status", %{conn: conn} do
user = insert(:user) user = insert(:user)
@ -946,7 +973,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false assert User.following?(other_user, user) == false
assert user.info.follow_request_count == 1
conn = conn =
build_conn() build_conn()
@ -960,7 +986,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == true assert User.following?(other_user, user) == true
assert user.info.follow_request_count == 0
end end
test "verify_credentials", %{conn: conn} do test "verify_credentials", %{conn: conn} do
@ -982,7 +1007,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
{:ok, _activity} = ActivityPub.follow(other_user, user) {:ok, _activity} = ActivityPub.follow(other_user, user)
user = Repo.get(User, user.id) user = Repo.get(User, user.id)
assert user.info.follow_request_count == 1
conn = conn =
build_conn() build_conn()
@ -996,7 +1020,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false assert User.following?(other_user, user) == false
assert user.info.follow_request_count == 0
end end
end end
@ -1932,4 +1955,36 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|> json_response(400) |> json_response(400)
end end
end end
describe "link headers" do
test "preserves parameters in link headers", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, activity1} =
CommonAPI.post(other_user, %{
"status" => "hi @#{user.nickname}",
"visibility" => "public"
})
{:ok, activity2} =
CommonAPI.post(other_user, %{
"status" => "hi @#{user.nickname}",
"visibility" => "public"
})
notification1 = Repo.get_by(Notification, activity_id: activity1.id)
notification2 = Repo.get_by(Notification, activity_id: activity2.id)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/notifications", %{media_only: true})
assert [link_header] = get_resp_header(conn, "link")
assert link_header =~ ~r/media_only=true/
assert link_header =~ ~r/since_id=#{notification2.id}/
assert link_header =~ ~r/max_id=#{notification1.id}/
end
end
end end

View file

@ -0,0 +1,23 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.PushSubscriptionViewTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
alias Pleroma.Web.Push
test "Represent a subscription" do
subscription = insert(:push_subscription, data: %{"alerts" => %{"mention" => true}})
expected = %{
alerts: %{"mention" => true},
endpoint: subscription.endpoint,
id: to_string(subscription.id),
server_key: Keyword.get(Push.vapid_config(), :public_key)
}
assert expected == View.render("push_subscription.json", %{subscription: subscription})
end
end

View file

@ -0,0 +1,192 @@
# 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.SubscriptionControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
@sub %{
"endpoint" => "https://example.com/example/1234",
"keys" => %{
"auth" => "8eDyX_uCN0XRhSbY5hs7Hg==",
"p256dh" =>
"BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA="
}
}
@server_key Keyword.get(Push.vapid_config(), :public_key)
setup do
user = insert(:user)
token = insert(:oauth_token, user: user, scopes: ["push"])
conn =
build_conn()
|> assign(:user, user)
|> assign(:token, token)
%{conn: conn, user: user, token: token}
end
defmacro assert_error_when_disable_push(do: yield) do
quote do
vapid_details = Application.get_env(:web_push_encryption, :vapid_details, [])
Application.put_env(:web_push_encryption, :vapid_details, [])
assert "Something went wrong" == unquote(yield)
Application.put_env(:web_push_encryption, :vapid_details, vapid_details)
end
end
describe "creates push subscription" do
test "returns error when push disabled ", %{conn: conn} do
assert_error_when_disable_push do
conn
|> post("/api/v1/push/subscription", %{})
|> json_response(500)
end
end
test "successful creation", %{conn: conn} do
result =
conn
|> post("/api/v1/push/subscription", %{
"data" => %{"alerts" => %{"mention" => true, "test" => true}},
"subscription" => @sub
})
|> json_response(200)
[subscription] = Pleroma.Repo.all(Subscription)
assert %{
"alerts" => %{"mention" => true},
"endpoint" => subscription.endpoint,
"id" => to_string(subscription.id),
"server_key" => @server_key
} == result
end
end
describe "gets a user subscription" do
test "returns error when push disabled ", %{conn: conn} do
assert_error_when_disable_push do
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(500)
end
end
test "returns error when user hasn't subscription", %{conn: conn} do
res =
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(404)
assert "Not found" == res
end
test "returns a user subsciption", %{conn: conn, user: user, token: token} do
subscription =
insert(:push_subscription,
user: user,
token: token,
data: %{"alerts" => %{"mention" => true}}
)
res =
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(200)
expect = %{
"alerts" => %{"mention" => true},
"endpoint" => "https://example.com/example/1234",
"id" => to_string(subscription.id),
"server_key" => @server_key
}
assert expect == res
end
end
describe "updates a user subsciption" do
setup %{conn: conn, user: user, token: token} do
subscription =
insert(:push_subscription,
user: user,
token: token,
data: %{"alerts" => %{"mention" => true}}
)
%{conn: conn, user: user, token: token, subscription: subscription}
end
test "returns error when push disabled ", %{conn: conn} do
assert_error_when_disable_push do
conn
|> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}})
|> json_response(500)
end
end
test "returns updated subsciption", %{conn: conn, subscription: subscription} do
res =
conn
|> put("/api/v1/push/subscription", %{
data: %{"alerts" => %{"mention" => false, "follow" => true}}
})
|> json_response(200)
expect = %{
"alerts" => %{"follow" => true, "mention" => false},
"endpoint" => "https://example.com/example/1234",
"id" => to_string(subscription.id),
"server_key" => @server_key
}
assert expect == res
end
end
describe "deletes the user subscription" do
test "returns error when push disabled ", %{conn: conn} do
assert_error_when_disable_push do
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(500)
end
end
test "returns error when user hasn't subscription", %{conn: conn} do
res =
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(404)
assert "Not found" == res
end
test "returns empty result and delete user subsciption", %{
conn: conn,
user: user,
token: token
} do
subscription =
insert(:push_subscription,
user: user,
token: token,
data: %{"alerts" => %{"mention" => true}}
)
res =
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(200)
assert %{} == res
refute Pleroma.Repo.get(Subscription, subscription.id)
end
end
end

View file

@ -8,7 +8,8 @@ defmodule Pleroma.Web.NodeInfoTest do
import Pleroma.Factory import Pleroma.Factory
test "nodeinfo shows staff accounts", %{conn: conn} do test "nodeinfo shows staff accounts", %{conn: conn} do
user = insert(:user, %{local: true, info: %{is_moderator: true}}) moderator = insert(:user, %{local: true, info: %{is_moderator: true}})
admin = insert(:user, %{local: true, info: %{is_admin: true}})
conn = conn =
conn conn
@ -16,7 +17,8 @@ defmodule Pleroma.Web.NodeInfoTest do
assert result = json_response(conn, 200) assert result = json_response(conn, 200)
assert user.ap_id in result["metadata"]["staffAccounts"] assert moderator.ap_id in result["metadata"]["staffAccounts"]
assert admin.ap_id in result["metadata"]["staffAccounts"]
end end
test "nodeinfo shows restricted nicknames", %{conn: conn} do test "nodeinfo shows restricted nicknames", %{conn: conn} do

145
test/web/push/impl_test.exs Normal file
View file

@ -0,0 +1,145 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.ImplTest do
use Pleroma.DataCase
alias Pleroma.Web.Push.Impl
alias Pleroma.Web.Push.Subscription
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn
%{method: :post, url: "https://example.com/example/1234"} ->
%Tesla.Env{status: 200}
%{method: :post, url: "https://example.com/example/not_found"} ->
%Tesla.Env{status: 400}
%{method: :post, url: "https://example.com/example/bad"} ->
%Tesla.Env{status: 100}
end)
:ok
end
@sub %{
endpoint: "https://example.com/example/1234",
keys: %{
auth: "8eDyX_uCN0XRhSbY5hs7Hg==",
p256dh:
"BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA="
}
}
@api_key "BASgACIHpN1GYgzSRp"
@message "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
test "performs sending notifications" do
user = insert(:user)
user2 = insert(:user)
insert(:push_subscription, user: user, data: %{alerts: %{"mention" => true}})
insert(:push_subscription, user: user2, data: %{alerts: %{"mention" => true}})
insert(:push_subscription,
user: user,
data: %{alerts: %{"follow" => true, "mention" => true}}
)
insert(:push_subscription,
user: user,
data: %{alerts: %{"follow" => true, "mention" => false}}
)
notif =
insert(:notification,
user: user,
activity: %Pleroma.Activity{
data: %{
"type" => "Create",
"actor" => user.ap_id,
"object" => %{"content" => "<Lorem ipsum dolor sit amet."}
}
}
)
assert Impl.perform_send(notif) == [:ok, :ok]
end
test "returns error if notif does not match " do
assert Impl.perform_send(%{}) == :error
end
test "successful message sending" do
assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
end
test "fail message sending" do
assert Impl.push_message(
@message,
Map.merge(@sub, %{endpoint: "https://example.com/example/bad"}),
@api_key,
%Subscription{}
) == :error
end
test "delete subsciption if restult send message between 400..500" do
subscription = insert(:push_subscription)
assert Impl.push_message(
@message,
Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}),
@api_key,
subscription
) == :ok
refute Pleroma.Repo.get(Subscription, subscription.id)
end
test "renders body for create activity" do
assert Impl.format_body(
%{
activity: %{
data: %{
"type" => "Create",
"object" => %{
"content" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis."
}
}
}
},
%{nickname: "Bob"}
) ==
"@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
end
test "renders body for follow activity" do
assert Impl.format_body(%{activity: %{data: %{"type" => "Follow"}}}, %{nickname: "Bob"}) ==
"@Bob has followed you"
end
test "renders body for announce activity" do
user = insert(:user)
note =
insert(:note, %{
data: %{
"content" =>
"<span>Lorem ipsum dolor sit amet</span>, consectetur :bear: adipiscing elit. Fusce sagittis finibus turpis."
}
})
note_activity = insert(:note_activity, %{note: note})
announce_activity = insert(:announce_activity, %{user: user, note_activity: note_activity})
assert Impl.format_body(%{activity: announce_activity}, user) ==
"@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
end
test "renders body for like activity" do
assert Impl.format_body(%{activity: %{data: %{"type" => "Like"}}}, %{nickname: "Bob"}) ==
"@Bob has favorited your post"
end
end

67
test/web/rel_me_test.exs Normal file
View file

@ -0,0 +1,67 @@
defmodule Pleroma.Web.RelMeTest do
use ExUnit.Case, async: true
setup do
Tesla.Mock.mock(fn
%{
method: :get,
url: "http://example.com/rel_me/anchor"
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_anchor.html")}
%{
method: :get,
url: "http://example.com/rel_me/anchor_nofollow"
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_anchor_nofollow.html")}
%{
method: :get,
url: "http://example.com/rel_me/link"
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_link.html")}
%{
method: :get,
url: "http://example.com/rel_me/null"
} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rel_me_null.html")}
end)
:ok
end
test "parse/1" do
hrefs = ["https://social.example.org/users/lain"]
assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/null") == {:ok, []}
assert {:error, _} = Pleroma.Web.RelMe.parse("http://example.com/rel_me/error")
assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/link") == {:ok, hrefs}
assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/anchor") == {:ok, hrefs}
assert Pleroma.Web.RelMe.parse("http://example.com/rel_me/anchor_nofollow") == {:ok, hrefs}
end
test "maybe_put_rel_me/2" do
profile_urls = ["https://social.example.org/users/lain"]
attr = "me"
fallback = nil
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/null", profile_urls) ==
fallback
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/error", profile_urls) ==
fallback
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/anchor", profile_urls) ==
attr
assert Pleroma.Web.RelMe.maybe_put_rel_me(
"http://example.com/rel_me/anchor_nofollow",
profile_urls
) == attr
assert Pleroma.Web.RelMe.maybe_put_rel_me("http://example.com/rel_me/link", profile_urls) ==
attr
end
end

View file

@ -0,0 +1,62 @@
defmodule Pleroma.Web.RichMedia.HelpersTest do
use Pleroma.DataCase
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
import Tesla.Mock
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
test "refuses to crawl incomplete URLs" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "[test](example.com/ogp)",
"content_type" => "text/markdown"
})
Pleroma.Config.put([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
Pleroma.Config.put([:rich_media, :enabled], false)
end
test "refuses to crawl malformed URLs" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "[test](example.com[]/ogp)",
"content_type" => "text/markdown"
})
Pleroma.Config.put([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
Pleroma.Config.put([:rich_media, :enabled], false)
end
test "crawls valid, complete URLs" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "[test](http://example.com/ogp)",
"content_type" => "text/markdown"
})
Pleroma.Config.put([:rich_media, :enabled], true)
assert %{page_url: "http://example.com/ogp", rich_media: _} =
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
Pleroma.Config.put([:rich_media, :enabled], false)
end
end

View file

@ -415,6 +415,33 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
assert status["id"] == direct_two.id assert status["id"] == direct_two.id
assert status_two["id"] == direct.id assert status_two["id"] == direct.id
end end
test "doesn't include DMs from blocked users", %{conn: conn} do
blocker = insert(:user)
blocked = insert(:user)
user = insert(:user)
{:ok, blocker} = User.block(blocker, blocked)
{:ok, _blocked_direct} =
CommonAPI.post(blocked, %{
"status" => "Hi @#{blocker.nickname}!",
"visibility" => "direct"
})
{:ok, direct} =
CommonAPI.post(user, %{
"status" => "Hi @#{blocker.nickname}!",
"visibility" => "direct"
})
res_conn =
conn
|> assign(:user, blocker)
|> get("/api/statuses/dm_timeline.json")
[status] = json_response(res_conn, 200)
assert status["id"] == direct.id
end
end end
describe "GET /statuses/mentions.json" do describe "GET /statuses/mentions.json" do
@ -427,7 +454,10 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
test "with credentials", %{conn: conn, user: current_user} do test "with credentials", %{conn: conn, user: current_user} do
{:ok, activity} = {:ok, activity} =
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user}) CommonAPI.post(current_user, %{
"status" => "why is tenshi eating a corndog so cute?",
"visibility" => "public"
})
conn = conn =
conn conn
@ -445,6 +475,23 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
mentioned: [current_user] mentioned: [current_user]
}) })
end end
test "does not show DMs in mentions timeline", %{conn: conn, user: current_user} do
{:ok, _activity} =
CommonAPI.post(current_user, %{
"status" => "Have you guys ever seen how cute tenshi eating a corndog is?",
"visibility" => "direct"
})
conn =
conn
|> with_credentials(current_user.nickname, "test")
|> get("/api/statuses/mentions.json")
response = json_response(conn, 200)
assert length(response) == 0
end
end end
describe "GET /api/qvitter/statuses/notifications.json" do describe "GET /api/qvitter/statuses/notifications.json" do
@ -670,7 +717,6 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
followed = Repo.get(User, followed.id) followed = Repo.get(User, followed.id)
refute User.ap_followers(followed) in current_user.following refute User.ap_followers(followed) in current_user.following
assert followed.info.follow_request_count == 1
assert json_response(conn, 200) == assert json_response(conn, 200) ==
UserView.render("show.json", %{user: followed, for: current_user}) UserView.render("show.json", %{user: followed, for: current_user})
@ -1737,19 +1783,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false assert User.following?(other_user, user) == false
assert user.info.follow_request_count == 1
conn = conn =
build_conn() build_conn()
|> assign(:user, user) |> assign(:user, user)
|> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id}) |> post("/api/pleroma/friendships/approve", %{"user_id" => other_user.id})
user = Repo.get(User, user.id)
assert relationship = json_response(conn, 200) assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"] assert other_user.id == relationship["id"]
assert relationship["follows_you"] == true assert relationship["follows_you"] == true
assert user.info.follow_request_count == 0
end end
end end
@ -1764,19 +1806,15 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
other_user = Repo.get(User, other_user.id) other_user = Repo.get(User, other_user.id)
assert User.following?(other_user, user) == false assert User.following?(other_user, user) == false
assert user.info.follow_request_count == 1
conn = conn =
build_conn() build_conn()
|> assign(:user, user) |> assign(:user, user)
|> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id}) |> post("/api/pleroma/friendships/deny", %{"user_id" => other_user.id})
user = Repo.get(User, user.id)
assert relationship = json_response(conn, 200) assert relationship = json_response(conn, 200)
assert other_user.id == relationship["id"] assert other_user.id == relationship["id"]
assert relationship["follows_you"] == false assert relationship["follows_you"] == false
assert user.info.follow_request_count == 0
end end
end end