forked from AkkomaGang/akkoma
Merge branch 'feld/pleroma-feld-mastodon-usersearch' into develop
This commit is contained in:
commit
f23edd2d6b
19 changed files with 87 additions and 14 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
BIN
priv/static/static/js/app.37dc091547e5c8fb0a0e.js
Normal file
BIN
priv/static/static/js/app.37dc091547e5c8fb0a0e.js
Normal file
Binary file not shown.
BIN
priv/static/static/js/app.37dc091547e5c8fb0a0e.js.map
Normal file
BIN
priv/static/static/js/app.37dc091547e5c8fb0a0e.js.map
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
priv/static/static/js/manifest.5e2e6cbffed3dea6be7c.js
Normal file
BIN
priv/static/static/js/manifest.5e2e6cbffed3dea6be7c.js
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
priv/static/static/js/vendor.a940853cbf3c748efda4.js.map
Normal file
BIN
priv/static/static/js/vendor.a940853cbf3c748efda4.js.map
Normal file
Binary file not shown.
|
@ -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"})
|
||||||
|
|
Loading…
Reference in a new issue