Merge branch 'feld/pleroma-feld-mastodon-usersearch' into develop

This commit is contained in:
Roger Braun 2017-10-30 19:25:32 +01:00
commit f23edd2d6b
19 changed files with 87 additions and 14 deletions

View file

@ -24,7 +24,7 @@ def change(struct, params \\ %{}) do
def get_by_ap_id(nil), do: nil def get_by_ap_id(nil), do: nil
def get_by_ap_id(ap_id) do def get_by_ap_id(ap_id) do
Repo.one(from object in Object, Repo.one(from object in Object,
where: fragment("? @> ?", object.data, ^%{id: ap_id})) where: fragment("(?)->>'id' = ?", object.data, ^ap_id))
end end
def get_cached_by_ap_id(ap_id) do def get_cached_by_ap_id(ap_id) do

View file

@ -241,7 +241,7 @@ def get_friends(%User{id: id, following: following}) do
def update_note_count(%User{} = user) do def update_note_count(%User{} = user) do
note_count_query = from a in Object, note_count_query = from a in Object,
where: fragment("? @> ?", a.data, ^%{actor: user.ap_id, type: "Note"}), where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data),
select: count(a.id) select: count(a.id)
note_count = Repo.one(note_count_query) note_count = Repo.one(note_count_query)
@ -274,4 +274,14 @@ def get_notified_from_activity(%Activity{data: %{"to" => to}} = activity) do
Repo.all(query) Repo.all(query)
end end
def search(query, resolve) do
if resolve do
User.get_or_fetch_by_nickname(query)
end
q = from u in User,
where: fragment("(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)", u.nickname, u.name, ^query),
limit: 20
Repo.all(q)
end
end end

View file

@ -90,7 +90,11 @@ def update_object_in_activities(%{data: %{"id" => id}} = object) do
""" """
def get_existing_like(actor, %{data: %{"id" => id}} = object) do def get_existing_like(actor, %{data: %{"id" => id}} = object) do
query = from activity in Activity, query = from activity in Activity,
where: fragment("? @> ?", activity.data, ^%{actor: actor, object: id, type: "Like"}) where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
# this is to use the index
where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^id),
where: fragment("(?)->>'type' = 'Like'", activity.data)
Repo.one(query) Repo.one(query)
end end

View file

@ -271,9 +271,27 @@ def following(conn, %{"id" => id}) 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.follow(follower, followed), {:ok, follower} <- User.follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed) do {:ok, activity} <- ActivityPub.follow(follower, followed) do
render conn, AccountView, "relationship.json", %{user: follower, target: followed} render conn, AccountView, "relationship.json", %{user: follower, target: followed}
else
{:error, message} = err ->
conn
|> put_resp_content_type("application/json")
|> send_resp(403, Poison.encode!(%{"error" => message}))
end
end
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
with %User{} = followed <- Repo.get_by(User, nickname: uri),
{:ok, follower} <- User.follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed) do
render conn, AccountView, "account.json", %{user: followed}
else
{:error, message} = err ->
conn
|> put_resp_content_type("application/json")
|> send_resp(403, Poison.encode!(%{"error" => message}))
end end
end end
@ -291,14 +309,7 @@ def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
end end
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
if params["resolve"] == "true" do accounts = User.search(query, params["resolve"] == "true")
User.get_or_fetch_by_nickname(query)
end
q = from u in User,
where: fragment("(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)", u.nickname, u.name, ^query),
limit: 20
accounts = Repo.all(q)
q = from a in Activity, q = from a in Activity,
where: fragment("?->>'type' = 'Create'", a.data), where: fragment("?->>'type' = 'Create'", a.data),
@ -315,6 +326,14 @@ def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
json(conn, res) json(conn, res)
end end
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true")
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
json(conn, res)
end
def favourites(%{assigns: %{user: user}} = conn, params) do def favourites(%{assigns: %{user: user}} = conn, params) do
params = conn params = conn
|> Map.put("type", "Create") |> Map.put("type", "Create")

View file

@ -55,6 +55,7 @@ def user_fetcher(username) do
get "/accounts/verify_credentials", MastodonAPIController, :verify_credentials get "/accounts/verify_credentials", MastodonAPIController, :verify_credentials
get "/accounts/relationships", MastodonAPIController, :relationships get "/accounts/relationships", MastodonAPIController, :relationships
get "/accounts/search", MastodonAPIController, :account_search
post "/accounts/:id/follow", MastodonAPIController, :follow post "/accounts/:id/follow", MastodonAPIController, :follow
post "/accounts/:id/unfollow", MastodonAPIController, :unfollow post "/accounts/:id/unfollow", MastodonAPIController, :unfollow
post "/accounts/:id/block", MastodonAPIController, :relationship_noop post "/accounts/:id/block", MastodonAPIController, :relationship_noop
@ -62,6 +63,8 @@ def user_fetcher(username) do
post "/accounts/:id/mute", MastodonAPIController, :relationship_noop post "/accounts/:id/mute", MastodonAPIController, :relationship_noop
post "/accounts/:id/unmute", MastodonAPIController, :relationship_noop post "/accounts/:id/unmute", MastodonAPIController, :relationship_noop
post "/follows", MastodonAPIController, :follow
get "/blocks", MastodonAPIController, :empty_array get "/blocks", MastodonAPIController, :empty_array
get "/domain_blocks", MastodonAPIController, :empty_array get "/domain_blocks", MastodonAPIController, :empty_array
get "/follow_requests", MastodonAPIController, :empty_array get "/follow_requests", MastodonAPIController, :empty_array

View file

@ -0,0 +1,7 @@
defmodule Pleroma.Repo.Migrations.DropObjectIndex do
use Ecto.Migration
def change do
drop_if_exists index(:objects, [:data], using: :gin)
end
end

View file

@ -0,0 +1,9 @@
defmodule Pleroma.Repo.Migrations.AddObjectActorIndex do
use Ecto.Migration
@disable_ddl_transaction true
def change do
create index(:objects, ["(data->>'actor')", "(data->>'type')"], concurrently: true, name: :objects_actor_type)
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><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.9cfa0ec1ee2d157fc360f5a3f1ee687c.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.13905a962b52e27fb039.js></script><script type=text/javascript src=/static/js/vendor.5ae36edd0f238a1334af.js></script><script type=text/javascript src=/static/js/app.437f43ecaf6ade101b9a.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><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.9cfa0ec1ee2d157fc360f5a3f1ee687c.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.5e2e6cbffed3dea6be7c.js></script><script type=text/javascript src=/static/js/vendor.a940853cbf3c748efda4.js></script><script type=text/javascript src=/static/js/app.37dc091547e5c8fb0a0e.js></script></body></html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -281,6 +281,14 @@ test "following / unfollowing a user", %{conn: conn} do
|> post("/api/v1/accounts/#{other_user.id}/unfollow") |> post("/api/v1/accounts/#{other_user.id}/unfollow")
assert %{"id" => id, "following" => false} = json_response(conn, 200) assert %{"id" => id, "following" => false} = json_response(conn, 200)
user = Repo.get(User, user.id)
conn = build_conn()
|> assign(:user, user)
|> post("/api/v1/follows", %{"uri" => other_user.nickname})
assert %{"id" => id} = json_response(conn, 200)
assert id == other_user.id
end end
test "unimplemented block/mute endpoints" do test "unimplemented block/mute endpoints" do
@ -311,6 +319,19 @@ test "unimplemented mutes, follow_requests, blocks, domain blocks" do
end) end)
end end
test "account seach", %{conn: conn} do
user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"})
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
conn = conn
|> assign(:user, user)
|> get("/api/v1/accounts/search", %{"q" => "2hu"})
assert [account] = json_response(conn, 200)
assert account["id"] == user_three.id
end
test "search", %{conn: conn} do test "search", %{conn: conn} do
user = insert(:user) user = insert(:user)
user_two = insert(:user, %{nickname: "shp@shitposter.club"}) user_two = insert(:user, %{nickname: "shp@shitposter.club"})