Merge develop
This commit is contained in:
commit
f1f7a11222
82 changed files with 1461 additions and 300 deletions
|
|
@ -109,7 +109,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
])
|
||||
)
|
||||
|
||||
binary_archive = Tesla.get!(src_url).body
|
||||
binary_archive = Tesla.get!(client(), src_url).body
|
||||
archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
|
||||
|
||||
sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
|
||||
|
|
@ -137,7 +137,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
])
|
||||
)
|
||||
|
||||
files = Tesla.get!(files_url).body |> Poison.decode!()
|
||||
files = Tesla.get!(client(), files_url).body |> Poison.decode!()
|
||||
|
||||
IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
|
||||
IO.puts("Downloading the pack and generating SHA256")
|
||||
|
||||
binary_archive = Tesla.get!(src).body
|
||||
binary_archive = Tesla.get!(client(), src).body
|
||||
archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
|
||||
|
||||
IO.puts("SHA256 is #{archive_sha}")
|
||||
|
|
@ -272,7 +272,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
defp fetch_manifest(from) do
|
||||
Poison.decode!(
|
||||
if String.starts_with?(from, "http") do
|
||||
Tesla.get!(from).body
|
||||
Tesla.get!(client(), from).body
|
||||
else
|
||||
File.read!(from)
|
||||
end
|
||||
|
|
@ -290,4 +290,12 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
]
|
||||
)
|
||||
end
|
||||
|
||||
defp client do
|
||||
middleware = [
|
||||
{Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
|
||||
]
|
||||
|
||||
Tesla.client(middleware)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -287,6 +287,29 @@ defmodule Pleroma.Activity do
|
|||
|> Repo.all()
|
||||
end
|
||||
|
||||
def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do
|
||||
from(
|
||||
a in Activity,
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'type' = 'Follow'",
|
||||
a.data
|
||||
),
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'state' = 'pending'",
|
||||
a.data
|
||||
),
|
||||
where:
|
||||
fragment(
|
||||
"coalesce((?)->'object'->>'id', (?)->>'object') = ?",
|
||||
a.data,
|
||||
a.data,
|
||||
^ap_id
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
@spec query_by_actor(actor()) :: Ecto.Query.t()
|
||||
def query_by_actor(actor) do
|
||||
from(a in Activity, where: a.actor == ^actor)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ defmodule Pleroma.Stats do
|
|||
def update_stats do
|
||||
peers =
|
||||
from(
|
||||
u in Pleroma.User,
|
||||
u in User,
|
||||
select: fragment("distinct split_part(?, '@', 2)", u.nickname),
|
||||
where: u.local != ^true
|
||||
)
|
||||
|
|
@ -44,10 +44,13 @@ defmodule Pleroma.Stats do
|
|||
domain_count = Enum.count(peers)
|
||||
|
||||
status_query =
|
||||
from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info))
|
||||
from(u in User.Query.build(%{local: true}),
|
||||
select: fragment("sum((?->>'note_count')::int)", u.info)
|
||||
)
|
||||
|
||||
status_count = Repo.one(status_query)
|
||||
user_count = Repo.aggregate(User.active_local_user_query(), :count, :id)
|
||||
|
||||
user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id)
|
||||
|
||||
Agent.update(__MODULE__, fn _ ->
|
||||
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
|
||||
|
|
|
|||
|
|
@ -255,10 +255,7 @@ defmodule Pleroma.User do
|
|||
candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames])
|
||||
|
||||
autofollowed_users =
|
||||
from(u in User,
|
||||
where: u.local == true,
|
||||
where: u.nickname in ^candidates
|
||||
)
|
||||
User.Query.build(%{nickname: candidates, local: true})
|
||||
|> Repo.all()
|
||||
|
||||
follow_all(user, autofollowed_users)
|
||||
|
|
@ -577,19 +574,17 @@ defmodule Pleroma.User do
|
|||
)
|
||||
end
|
||||
|
||||
def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do
|
||||
from(
|
||||
u in User,
|
||||
where: fragment("? <@ ?", ^[follower_address], u.following),
|
||||
where: u.id != ^id
|
||||
)
|
||||
@spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
|
||||
def get_followers_query(%User{} = user, nil) do
|
||||
User.Query.build(%{followers: user})
|
||||
end
|
||||
|
||||
def get_followers_query(user, page) do
|
||||
from(u in get_followers_query(user, nil))
|
||||
|> paginate(page, 20)
|
||||
|> User.Query.paginate(page, 20)
|
||||
end
|
||||
|
||||
@spec get_followers_query(User.t()) :: Ecto.Query.t()
|
||||
def get_followers_query(user), do: get_followers_query(user, nil)
|
||||
|
||||
def get_followers(user, page \\ nil) do
|
||||
|
|
@ -604,19 +599,17 @@ defmodule Pleroma.User do
|
|||
Repo.all(from(u in q, select: u.id))
|
||||
end
|
||||
|
||||
def get_friends_query(%User{id: id, following: following}, nil) do
|
||||
from(
|
||||
u in User,
|
||||
where: u.follower_address in ^following,
|
||||
where: u.id != ^id
|
||||
)
|
||||
@spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
|
||||
def get_friends_query(%User{} = user, nil) do
|
||||
User.Query.build(%{friends: user})
|
||||
end
|
||||
|
||||
def get_friends_query(user, page) do
|
||||
from(u in get_friends_query(user, nil))
|
||||
|> paginate(page, 20)
|
||||
|> User.Query.paginate(page, 20)
|
||||
end
|
||||
|
||||
@spec get_friends_query(User.t()) :: Ecto.Query.t()
|
||||
def get_friends_query(user), do: get_friends_query(user, nil)
|
||||
|
||||
def get_friends(user, page \\ nil) do
|
||||
|
|
@ -631,33 +624,10 @@ defmodule Pleroma.User do
|
|||
Repo.all(from(u in q, select: u.id))
|
||||
end
|
||||
|
||||
def get_follow_requests_query(%User{} = user) do
|
||||
from(
|
||||
a in Activity,
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'type' = 'Follow'",
|
||||
a.data
|
||||
),
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'state' = 'pending'",
|
||||
a.data
|
||||
),
|
||||
where:
|
||||
fragment(
|
||||
"coalesce((?)->'object'->>'id', (?)->>'object') = ?",
|
||||
a.data,
|
||||
a.data,
|
||||
^user.ap_id
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
@spec get_follow_requests(User.t()) :: {:ok, [User.t()]}
|
||||
def get_follow_requests(%User{} = user) do
|
||||
users =
|
||||
user
|
||||
|> User.get_follow_requests_query()
|
||||
Activity.follow_requests_for_actor(user)
|
||||
|> join(:inner, [a], u in User, on: a.actor == u.ap_id)
|
||||
|> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
|
||||
|> group_by([a, u], u.id)
|
||||
|
|
@ -730,10 +700,7 @@ defmodule Pleroma.User do
|
|||
|
||||
def update_follower_count(%User{} = user) do
|
||||
follower_count_query =
|
||||
User
|
||||
|> where([u], ^user.follower_address in u.following)
|
||||
|> where([u], u.id != ^user.id)
|
||||
|> select([u], %{count: count(u.id)})
|
||||
User.Query.build(%{followers: user}) |> select([u], %{count: count(u.id)})
|
||||
|
||||
User
|
||||
|> where(id: ^user.id)
|
||||
|
|
@ -756,38 +723,19 @@ defmodule Pleroma.User do
|
|||
end
|
||||
end
|
||||
|
||||
def get_users_from_set_query(ap_ids, false) do
|
||||
from(
|
||||
u in User,
|
||||
where: u.ap_id in ^ap_ids
|
||||
)
|
||||
end
|
||||
|
||||
def get_users_from_set_query(ap_ids, true) do
|
||||
query = get_users_from_set_query(ap_ids, false)
|
||||
|
||||
from(
|
||||
u in query,
|
||||
where: u.local == true
|
||||
)
|
||||
end
|
||||
|
||||
@spec get_users_from_set([String.t()], boolean()) :: [User.t()]
|
||||
def get_users_from_set(ap_ids, local_only \\ true) do
|
||||
get_users_from_set_query(ap_ids, local_only)
|
||||
criteria = %{ap_id: ap_ids}
|
||||
criteria = if local_only, do: Map.put(criteria, :local, true), else: criteria
|
||||
|
||||
User.Query.build(criteria)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec get_recipients_from_activity(Activity.t()) :: [User.t()]
|
||||
def get_recipients_from_activity(%Activity{recipients: to}) do
|
||||
query =
|
||||
from(
|
||||
u in User,
|
||||
where: u.ap_id in ^to,
|
||||
or_where: fragment("? && ?", u.following, ^to)
|
||||
)
|
||||
|
||||
query = from(u in query, where: u.local == true)
|
||||
|
||||
Repo.all(query)
|
||||
User.Query.build(%{recipients_from_activity: to, local: true})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def search(query, resolve \\ false, for_user \\ nil) do
|
||||
|
|
@ -1049,14 +997,23 @@ defmodule Pleroma.User do
|
|||
end
|
||||
end
|
||||
|
||||
def muted_users(user),
|
||||
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes))
|
||||
@spec muted_users(User.t()) :: [User.t()]
|
||||
def muted_users(user) do
|
||||
User.Query.build(%{ap_id: user.info.mutes})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def blocked_users(user),
|
||||
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks))
|
||||
@spec blocked_users(User.t()) :: [User.t()]
|
||||
def blocked_users(user) do
|
||||
User.Query.build(%{ap_id: user.info.blocks})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def subscribers(user),
|
||||
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscribers))
|
||||
@spec subscribers(User.t()) :: [User.t()]
|
||||
def subscribers(user) do
|
||||
User.Query.build(%{ap_id: user.info.subscribers})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def block_domain(user, domain) do
|
||||
info_cng =
|
||||
|
|
@ -1082,69 +1039,6 @@ defmodule Pleroma.User do
|
|||
update_and_set_cache(cng)
|
||||
end
|
||||
|
||||
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(
|
||||
u in query,
|
||||
where: u.local == true,
|
||||
where: not is_nil(u.nickname)
|
||||
)
|
||||
end
|
||||
|
||||
def maybe_external_user_query(query, external) do
|
||||
if external, do: external_user_query(query), else: query
|
||||
end
|
||||
|
||||
def external_user_query(query \\ User) do
|
||||
from(
|
||||
u in query,
|
||||
where: u.local == false,
|
||||
where: not is_nil(u.nickname)
|
||||
)
|
||||
end
|
||||
|
||||
def maybe_active_user_query(query, active) do
|
||||
if active, do: active_user_query(query), else: query
|
||||
end
|
||||
|
||||
def active_user_query(query \\ User) do
|
||||
from(
|
||||
u in query,
|
||||
where: fragment("not (?->'deactivated' @> 'true')", u.info),
|
||||
where: not is_nil(u.nickname)
|
||||
)
|
||||
end
|
||||
|
||||
def maybe_deactivated_user_query(query, deactivated) do
|
||||
if deactivated, do: deactivated_user_query(query), else: query
|
||||
end
|
||||
|
||||
def deactivated_user_query(query \\ User) do
|
||||
from(
|
||||
u in query,
|
||||
where: fragment("(?->'deactivated' @> 'true')", u.info),
|
||||
where: not is_nil(u.nickname)
|
||||
)
|
||||
end
|
||||
|
||||
def active_local_user_query do
|
||||
from(
|
||||
u in local_user_query(),
|
||||
where: fragment("not (?->'deactivated' @> 'true')", u.info)
|
||||
)
|
||||
end
|
||||
|
||||
def moderator_user_query do
|
||||
from(
|
||||
u in User,
|
||||
where: u.local == true,
|
||||
where: fragment("?->'is_moderator' @> 'true'", u.info)
|
||||
)
|
||||
end
|
||||
|
||||
def deactivate(%User{} = user, status \\ true) do
|
||||
info_cng = User.Info.set_activation_status(user.info, status)
|
||||
|
||||
|
|
@ -1307,7 +1201,7 @@ defmodule Pleroma.User do
|
|||
def ap_enabled?(_), do: false
|
||||
|
||||
@doc "Gets or fetch a user by uri or nickname."
|
||||
@spec get_or_fetch(String.t()) :: User.t()
|
||||
@spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
|
||||
def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri)
|
||||
def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname)
|
||||
|
||||
|
|
@ -1424,22 +1318,12 @@ defmodule Pleroma.User do
|
|||
}
|
||||
end
|
||||
|
||||
@spec all_superusers() :: [User.t()]
|
||||
def all_superusers do
|
||||
from(
|
||||
u in User,
|
||||
where: u.local == true,
|
||||
where: fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info)
|
||||
)
|
||||
User.Query.build(%{super_users: true, local: true})
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
defp paginate(query, page, page_size) do
|
||||
from(u in query,
|
||||
limit: ^page_size,
|
||||
offset: ^((page - 1) * page_size)
|
||||
)
|
||||
end
|
||||
|
||||
def showing_reblogs?(%User{} = user, %User{} = target) do
|
||||
target.ap_id not in user.info.muted_reblogs
|
||||
end
|
||||
|
|
|
|||
150
lib/pleroma/user/query.ex
Normal file
150
lib/pleroma/user/query.ex
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.Query do
|
||||
@moduledoc """
|
||||
User query builder module. Builds query from new query or another user query.
|
||||
|
||||
## Example:
|
||||
query = Pleroma.User.Query(%{nickname: "nickname"})
|
||||
another_query = Pleroma.User.Query.build(query, %{email: "email@example.com"})
|
||||
Pleroma.Repo.all(query)
|
||||
Pleroma.Repo.all(another_query)
|
||||
|
||||
Adding new rules:
|
||||
- *ilike criteria*
|
||||
- add field to @ilike_criteria list
|
||||
- pass non empty string
|
||||
- e.g. Pleroma.User.Query.build(%{nickname: "nickname"})
|
||||
- *equal criteria*
|
||||
- add field to @equal_criteria list
|
||||
- pass non empty string
|
||||
- e.g. Pleroma.User.Query.build(%{email: "email@example.com"})
|
||||
- *contains criteria*
|
||||
- add field to @containns_criteria list
|
||||
- pass values list
|
||||
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
|
||||
"""
|
||||
import Ecto.Query
|
||||
import Pleroma.Web.AdminAPI.Search, only: [not_empty_string: 1]
|
||||
alias Pleroma.User
|
||||
|
||||
@type criteria ::
|
||||
%{
|
||||
query: String.t(),
|
||||
tags: [String.t()],
|
||||
name: String.t(),
|
||||
email: String.t(),
|
||||
local: boolean(),
|
||||
external: boolean(),
|
||||
active: boolean(),
|
||||
deactivated: boolean(),
|
||||
is_admin: boolean(),
|
||||
is_moderator: boolean(),
|
||||
super_users: boolean(),
|
||||
followers: User.t(),
|
||||
friends: User.t(),
|
||||
recipients_from_activity: [String.t()],
|
||||
nickname: [String.t()],
|
||||
ap_id: [String.t()]
|
||||
}
|
||||
| %{}
|
||||
|
||||
@ilike_criteria [:nickname, :name, :query]
|
||||
@equal_criteria [:email]
|
||||
@role_criteria [:is_admin, :is_moderator]
|
||||
@contains_criteria [:ap_id, :nickname]
|
||||
|
||||
@spec build(criteria()) :: Query.t()
|
||||
def build(query \\ base_query(), criteria) do
|
||||
prepare_query(query, criteria)
|
||||
end
|
||||
|
||||
@spec paginate(Ecto.Query.t(), pos_integer(), pos_integer()) :: Ecto.Query.t()
|
||||
def paginate(query, page, page_size) do
|
||||
from(u in query,
|
||||
limit: ^page_size,
|
||||
offset: ^((page - 1) * page_size)
|
||||
)
|
||||
end
|
||||
|
||||
defp base_query do
|
||||
from(u in User)
|
||||
end
|
||||
|
||||
defp prepare_query(query, criteria) do
|
||||
Enum.reduce(criteria, query, &compose_query/2)
|
||||
end
|
||||
|
||||
defp compose_query({key, value}, query)
|
||||
when key in @ilike_criteria and not_empty_string(value) do
|
||||
# hack for :query key
|
||||
key = if key == :query, do: :nickname, else: key
|
||||
where(query, [u], ilike(field(u, ^key), ^"%#{value}%"))
|
||||
end
|
||||
|
||||
defp compose_query({key, value}, query)
|
||||
when key in @equal_criteria and not_empty_string(value) do
|
||||
where(query, [u], ^[{key, value}])
|
||||
end
|
||||
|
||||
defp compose_query({key, values}, query) when key in @contains_criteria and is_list(values) do
|
||||
where(query, [u], field(u, ^key) in ^values)
|
||||
end
|
||||
|
||||
defp compose_query({:tags, tags}, query) when is_list(tags) and length(tags) > 0 do
|
||||
Enum.reduce(tags, query, &prepare_tag_criteria/2)
|
||||
end
|
||||
|
||||
defp compose_query({key, _}, query) when key in @role_criteria do
|
||||
where(query, [u], fragment("(?->? @> 'true')", u.info, ^to_string(key)))
|
||||
end
|
||||
|
||||
defp compose_query({:super_users, _}, query) do
|
||||
where(
|
||||
query,
|
||||
[u],
|
||||
fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info)
|
||||
)
|
||||
end
|
||||
|
||||
defp compose_query({:local, _}, query), do: location_query(query, true)
|
||||
|
||||
defp compose_query({:external, _}, query), do: location_query(query, false)
|
||||
|
||||
defp compose_query({:active, _}, query) do
|
||||
where(query, [u], fragment("not (?->'deactivated' @> 'true')", u.info))
|
||||
|> where([u], not is_nil(u.nickname))
|
||||
end
|
||||
|
||||
defp compose_query({:deactivated, _}, query) do
|
||||
where(query, [u], fragment("?->'deactivated' @> 'true'", u.info))
|
||||
|> where([u], not is_nil(u.nickname))
|
||||
end
|
||||
|
||||
defp compose_query({:followers, %User{id: id, follower_address: follower_address}}, query) do
|
||||
where(query, [u], fragment("? <@ ?", ^[follower_address], u.following))
|
||||
|> where([u], u.id != ^id)
|
||||
end
|
||||
|
||||
defp compose_query({:friends, %User{id: id, following: following}}, query) do
|
||||
where(query, [u], u.follower_address in ^following)
|
||||
|> where([u], u.id != ^id)
|
||||
end
|
||||
|
||||
defp compose_query({:recipients_from_activity, to}, query) do
|
||||
where(query, [u], u.ap_id in ^to or fragment("? && ?", u.following, ^to))
|
||||
end
|
||||
|
||||
defp compose_query(_unsupported_param, query), do: query
|
||||
|
||||
defp prepare_tag_criteria(tag, query) do
|
||||
or_where(query, [u], fragment("? = any(?)", ^tag, u.tags))
|
||||
end
|
||||
|
||||
defp location_query(query, local) do
|
||||
where(query, [u], u.local == ^local)
|
||||
|> where([u], not is_nil(u.nickname))
|
||||
end
|
||||
end
|
||||
|
|
@ -101,7 +101,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
search_params = %{
|
||||
query: params["query"],
|
||||
page: page,
|
||||
page_size: page_size
|
||||
page_size: page_size,
|
||||
tags: params["tags"],
|
||||
name: params["name"],
|
||||
email: params["email"]
|
||||
}
|
||||
|
||||
with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
|
||||
|
|
@ -116,11 +119,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
)
|
||||
end
|
||||
|
||||
@filters ~w(local external active deactivated)
|
||||
|
||||
defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
|
||||
@filters ~w(local external active deactivated is_admin is_moderator)
|
||||
|
||||
@spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
|
||||
defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
|
||||
|
||||
defp maybe_parse_filters(filters) do
|
||||
filters
|
||||
|> String.split(",")
|
||||
|
|
|
|||
|
|
@ -10,45 +10,23 @@ defmodule Pleroma.Web.AdminAPI.Search do
|
|||
|
||||
@page_size 50
|
||||
|
||||
def user(%{query: term} = params) when is_nil(term) or term == "" do
|
||||
query = maybe_filtered_query(params)
|
||||
defmacro not_empty_string(string) do
|
||||
quote do
|
||||
is_binary(unquote(string)) and unquote(string) != ""
|
||||
end
|
||||
end
|
||||
|
||||
@spec user(map()) :: {:ok, [User.t()], pos_integer()}
|
||||
def user(params \\ %{}) do
|
||||
query = User.Query.build(params) |> order_by([u], u.nickname)
|
||||
|
||||
paginated_query =
|
||||
maybe_filtered_query(params)
|
||||
|> paginate(params[:page] || 1, params[:page_size] || @page_size)
|
||||
User.Query.paginate(query, params[:page] || 1, params[:page_size] || @page_size)
|
||||
|
||||
count = query |> Repo.aggregate(:count, :id)
|
||||
count = Repo.aggregate(query, :count, :id)
|
||||
|
||||
results = Repo.all(paginated_query)
|
||||
|
||||
{:ok, results, count}
|
||||
end
|
||||
|
||||
def user(%{query: term} = params) when is_binary(term) do
|
||||
search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%"))
|
||||
|
||||
count = search_query |> Repo.aggregate(:count, :id)
|
||||
|
||||
results =
|
||||
search_query
|
||||
|> paginate(params[:page] || 1, params[:page_size] || @page_size)
|
||||
|> Repo.all()
|
||||
|
||||
{:ok, results, count}
|
||||
end
|
||||
|
||||
defp maybe_filtered_query(params) do
|
||||
from(u in User, order_by: u.nickname)
|
||||
|> User.maybe_local_user_query(params[:local])
|
||||
|> User.maybe_external_user_query(params[:external])
|
||||
|> User.maybe_active_user_query(params[:active])
|
||||
|> User.maybe_deactivated_user_query(params[:deactivated])
|
||||
end
|
||||
|
||||
defp paginate(query, page, page_size) do
|
||||
from(u in query,
|
||||
limit: ^page_size,
|
||||
offset: ^((page - 1) * page_size)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,12 +10,6 @@ defmodule Pleroma.Web.ControllerHelper do
|
|||
def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
|
||||
def truthy_param?(value), do: value not in @falsy_param_values
|
||||
|
||||
def oauth_scopes(params, default) do
|
||||
# Note: `scopes` is used by Mastodon — supporting it but sticking to
|
||||
# OAuth's standard `scope` wherever we control it
|
||||
Pleroma.Web.OAuth.parse_scopes(params["scope"] || params["scopes"], default)
|
||||
end
|
||||
|
||||
def json_response(conn, status, json) do
|
||||
conn
|
||||
|> put_status(status)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@ defmodule Pleroma.Web.Endpoint do
|
|||
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
|
||||
)
|
||||
|
||||
plug(Plug.Static.IndexHtml, at: "/pleroma/admin/")
|
||||
|
||||
plug(Plug.Static,
|
||||
at: "/pleroma/admin/",
|
||||
from: {:pleroma, "priv/static/adminfe/"}
|
||||
)
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
# :code_reloader configuration of your endpoint.
|
||||
if code_reloading? do
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
alias Pleroma.Web.MediaProxy
|
||||
alias Pleroma.Web.OAuth.App
|
||||
alias Pleroma.Web.OAuth.Authorization
|
||||
alias Pleroma.Web.OAuth.Scopes
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
|
||||
alias Pleroma.Web.ControllerHelper
|
||||
|
|
@ -50,7 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
action_fallback(:errors)
|
||||
|
||||
def create_app(conn, params) do
|
||||
scopes = ControllerHelper.oauth_scopes(params, ["read"])
|
||||
scopes = Scopes.fetch_scopes(params, ["read"])
|
||||
|
||||
app_attrs =
|
||||
params
|
||||
|
|
|
|||
|
|
@ -3,18 +3,4 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth do
|
||||
def parse_scopes(scopes, _default) when is_list(scopes) do
|
||||
Enum.filter(scopes, &(&1 not in [nil, ""]))
|
||||
end
|
||||
|
||||
def parse_scopes(scopes, default) when is_binary(scopes) do
|
||||
scopes
|
||||
|> String.trim()
|
||||
|> String.split(~r/[\s,]+/)
|
||||
|> parse_scopes(default)
|
||||
end
|
||||
|
||||
def parse_scopes(_, default) do
|
||||
default
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
alias Pleroma.Web.OAuth.Token
|
||||
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
||||
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
|
||||
alias Pleroma.Web.OAuth.Scopes
|
||||
|
||||
if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth)
|
||||
|
||||
|
|
@ -57,7 +56,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
defp do_authorize(conn, params) do
|
||||
app = Repo.get_by(App, client_id: params["client_id"])
|
||||
available_scopes = (app && app.scopes) || []
|
||||
scopes = oauth_scopes(params, nil) || available_scopes
|
||||
scopes = Scopes.fetch_scopes(params, available_scopes)
|
||||
|
||||
# Note: `params` might differ from `conn.params`; use `@params` not `@conn.params` in template
|
||||
render(conn, Authenticator.auth_template(), %{
|
||||
|
|
@ -113,7 +112,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
|
||||
defp handle_create_authorization_error(
|
||||
conn,
|
||||
{scopes_issue, _},
|
||||
{:error, scopes_issue},
|
||||
%{"authorization" => _} = params
|
||||
)
|
||||
when scopes_issue in [:unsupported_scopes, :missing_scopes] do
|
||||
|
|
@ -184,9 +183,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
%App{} = app <- get_app_from_request(conn, params),
|
||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
||||
{:user_active, true} <- {:user_active, !user.info.deactivated},
|
||||
scopes <- oauth_scopes(params, app.scopes),
|
||||
[] <- scopes -- app.scopes,
|
||||
true <- Enum.any?(scopes),
|
||||
{:ok, scopes} <- validate_scopes(app, params),
|
||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||
json(conn, response_token(user, token))
|
||||
|
|
@ -247,8 +244,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
@doc "Prepares OAuth request to provider for Ueberauth"
|
||||
def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do
|
||||
scope =
|
||||
oauth_scopes(auth_attrs, [])
|
||||
|> Enum.join(" ")
|
||||
auth_attrs
|
||||
|> Scopes.fetch_scopes([])
|
||||
|> Scopes.to_string()
|
||||
|
||||
state =
|
||||
auth_attrs
|
||||
|
|
@ -326,7 +324,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
client_id: auth_attrs["client_id"],
|
||||
redirect_uri: auth_attrs["redirect_uri"],
|
||||
state: auth_attrs["state"],
|
||||
scopes: oauth_scopes(auth_attrs, []),
|
||||
scopes: Scopes.fetch_scopes(auth_attrs, []),
|
||||
nickname: auth_attrs["nickname"],
|
||||
email: auth_attrs["email"]
|
||||
})
|
||||
|
|
@ -401,10 +399,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
|
||||
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||
true <- redirect_uri in String.split(app.redirect_uris),
|
||||
scopes <- oauth_scopes(auth_attrs, []),
|
||||
{:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes},
|
||||
# Note: `scope` param is intentionally not optional in this context
|
||||
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
|
||||
{:ok, scopes} <- validate_scopes(app, auth_attrs),
|
||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
|
||||
Authorization.create_authorization(app, user, scopes)
|
||||
end
|
||||
|
|
@ -458,4 +453,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
}
|
||||
|> Map.merge(opts)
|
||||
end
|
||||
|
||||
@spec validate_scopes(App.t(), map()) ::
|
||||
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
|
||||
defp validate_scopes(app, params) do
|
||||
params
|
||||
|> Scopes.fetch_scopes(app.scopes)
|
||||
|> Scopes.validates(app.scopes)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
67
lib/pleroma/web/oauth/scopes.ex
Normal file
67
lib/pleroma/web/oauth/scopes.ex
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth.Scopes do
|
||||
@moduledoc """
|
||||
Functions for dealing with scopes.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Fetch scopes from requiest params.
|
||||
|
||||
Note: `scopes` is used by Mastodon — supporting it but sticking to
|
||||
OAuth's standard `scope` wherever we control it
|
||||
"""
|
||||
@spec fetch_scopes(map(), list()) :: list()
|
||||
def fetch_scopes(params, default) do
|
||||
parse_scopes(params["scope"] || params["scopes"], default)
|
||||
end
|
||||
|
||||
def parse_scopes(scopes, _default) when is_list(scopes) do
|
||||
Enum.filter(scopes, &(&1 not in [nil, ""]))
|
||||
end
|
||||
|
||||
def parse_scopes(scopes, default) when is_binary(scopes) do
|
||||
scopes
|
||||
|> to_list
|
||||
|> parse_scopes(default)
|
||||
end
|
||||
|
||||
def parse_scopes(_, default) do
|
||||
default
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert scopes string to list
|
||||
"""
|
||||
@spec to_list(binary()) :: [binary()]
|
||||
def to_list(nil), do: []
|
||||
|
||||
def to_list(str) do
|
||||
str
|
||||
|> String.trim()
|
||||
|> String.split(~r/[\s,]+/)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert scopes list to string
|
||||
"""
|
||||
@spec to_string(list()) :: binary()
|
||||
def to_string(scopes), do: Enum.join(scopes, " ")
|
||||
|
||||
@doc """
|
||||
Validates scopes.
|
||||
"""
|
||||
@spec validates(list() | nil, list()) ::
|
||||
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
|
||||
def validates([], _app_scopes), do: {:error, :missing_scopes}
|
||||
def validates(nil, _app_scopes), do: {:error, :missing_scopes}
|
||||
|
||||
def validates(scopes, app_scopes) do
|
||||
case scopes -- app_scopes do
|
||||
[] -> {:ok, scopes}
|
||||
_ -> {:error, :unsupported_scopes}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -170,7 +170,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
|
|||
created_at = activity.data["published"] |> Utils.date_to_asctime()
|
||||
announced_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
|
||||
|
||||
text = "#{user.nickname} retweeted a status."
|
||||
text = "#{user.nickname} repeated a status."
|
||||
|
||||
retweeted_status = render("activity.json", Map.merge(opts, %{activity: announced_activity}))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue