Merge branch '394_user_tags' into 'develop'
[#394] User tags Closes #394 See merge request pleroma/pleroma!508
This commit is contained in:
commit
94d8f1ab30
|
@ -2,6 +2,7 @@ defmodule Pleroma.User do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
import Ecto.{Changeset, Query}
|
import Ecto.{Changeset, Query}
|
||||||
|
alias Ecto.Multi
|
||||||
alias Pleroma.{Repo, User, Object, Web, Activity, Notification}
|
alias Pleroma.{Repo, User, Object, Web, Activity, Notification}
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
|
@ -23,6 +24,7 @@ defmodule Pleroma.User do
|
||||||
field(:local, :boolean, default: true)
|
field(:local, :boolean, default: true)
|
||||||
field(:follower_address, :string)
|
field(:follower_address, :string)
|
||||||
field(:search_distance, :float, virtual: true)
|
field(:search_distance, :float, virtual: true)
|
||||||
|
field(:tags, {:array, :string}, default: [])
|
||||||
field(:last_refreshed_at, :naive_datetime)
|
field(:last_refreshed_at, :naive_datetime)
|
||||||
has_many(:notifications, Notification)
|
has_many(:notifications, Notification)
|
||||||
embeds_one(:info, Pleroma.User.Info)
|
embeds_one(:info, Pleroma.User.Info)
|
||||||
|
@ -815,4 +817,41 @@ def parse_bio(bio, user \\ %User{info: %{source_data: %{}}}) do
|
||||||
|
|
||||||
CommonUtils.format_input(bio, mentions, tags, "text/plain") |> Formatter.emojify(emoji)
|
CommonUtils.format_input(bio, mentions, tags, "text/plain") |> Formatter.emojify(emoji)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tag(user_identifiers, tags) when is_list(user_identifiers) do
|
||||||
|
Repo.transaction(fn ->
|
||||||
|
for user_identifier <- user_identifiers, do: tag(user_identifier, tags)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def untag(user_identifiers, tags) when is_list(user_identifiers) do
|
||||||
|
Repo.transaction(fn ->
|
||||||
|
for user_identifier <- user_identifiers, do: untag(user_identifier, tags)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tag(nickname, tags) when is_binary(nickname), do: tag(User.get_by_nickname(nickname), tags)
|
||||||
|
|
||||||
|
def untag(nickname, tags) when is_binary(nickname),
|
||||||
|
do: untag(User.get_by_nickname(nickname), tags)
|
||||||
|
|
||||||
|
def tag(%User{} = user, tags),
|
||||||
|
do: update_tags(user, Enum.uniq(user.tags ++ normalize_tags(tags)))
|
||||||
|
|
||||||
|
def untag(%User{} = user, tags), do: update_tags(user, user.tags -- normalize_tags(tags))
|
||||||
|
|
||||||
|
defp update_tags(%User{} = user, new_tags) do
|
||||||
|
{:ok, updated_user} =
|
||||||
|
user
|
||||||
|
|> change(%{tags: new_tags})
|
||||||
|
|> Repo.update()
|
||||||
|
|
||||||
|
updated_user
|
||||||
|
end
|
||||||
|
|
||||||
|
defp normalize_tags(tags) do
|
||||||
|
[tags]
|
||||||
|
|> List.flatten()
|
||||||
|
|> Enum.map(&String.downcase(&1))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
alias Pleroma.{User, Repo}
|
alias Pleroma.{User, Repo}
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
|
|
||||||
|
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
action_fallback(:errors)
|
action_fallback(:errors)
|
||||||
|
@ -40,6 +42,16 @@ def user_create(
|
||||||
|> json(new_user.nickname)
|
|> json(new_user.nickname)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
|
||||||
|
with {:ok, _} <- User.tag(nicknames, tags),
|
||||||
|
do: json_response(conn, :no_content, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
|
||||||
|
with {:ok, _} <- User.untag(nicknames, tags),
|
||||||
|
do: json_response(conn, :no_content, "")
|
||||||
|
end
|
||||||
|
|
||||||
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
|
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
|
||||||
when permission_group in ["moderator", "admin"] do
|
when permission_group in ["moderator", "admin"] do
|
||||||
user = User.get_by_nickname(nickname)
|
user = User.get_by_nickname(nickname)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Pleroma.Web.ControllerHelper do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
def json_response(conn, status, json) do
|
||||||
|
conn
|
||||||
|
|> put_status(status)
|
||||||
|
|> json(json)
|
||||||
|
end
|
||||||
|
end
|
|
@ -58,6 +58,11 @@ def render("account.json", %{user: user} = opts) do
|
||||||
note: "",
|
note: "",
|
||||||
privacy: user_info.default_scope,
|
privacy: user_info.default_scope,
|
||||||
sensitive: false
|
sensitive: false
|
||||||
|
},
|
||||||
|
|
||||||
|
# Pleroma extension
|
||||||
|
pleroma: %{
|
||||||
|
tags: user.tags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -98,6 +98,8 @@ defmodule Pleroma.Web.Router do
|
||||||
pipe_through(:admin_api)
|
pipe_through(:admin_api)
|
||||||
delete("/user", AdminAPIController, :user_delete)
|
delete("/user", AdminAPIController, :user_delete)
|
||||||
post("/user", AdminAPIController, :user_create)
|
post("/user", AdminAPIController, :user_create)
|
||||||
|
put("/users/tag", AdminAPIController, :tag_users)
|
||||||
|
delete("/users/tag", AdminAPIController, :untag_users)
|
||||||
|
|
||||||
get("/permission_group/:nickname", AdminAPIController, :right_get)
|
get("/permission_group/:nickname", AdminAPIController, :right_get)
|
||||||
get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get)
|
get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get)
|
||||||
|
|
|
@ -77,7 +77,12 @@ def render("user.json", %{user: user = %User{}} = assigns) do
|
||||||
"locked" => user.info.locked,
|
"locked" => user.info.locked,
|
||||||
"default_scope" => user.info.default_scope,
|
"default_scope" => user.info.default_scope,
|
||||||
"no_rich_text" => user.info.no_rich_text,
|
"no_rich_text" => user.info.no_rich_text,
|
||||||
"fields" => fields
|
"fields" => fields,
|
||||||
|
|
||||||
|
# Pleroma extension
|
||||||
|
"pleroma" => %{
|
||||||
|
"tags" => user.tags
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if assigns[:token] do
|
if assigns[:token] do
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddTagsToUsers do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:users) do
|
||||||
|
add :tags, {:array, :string}
|
||||||
|
end
|
||||||
|
|
||||||
|
create index(:users, [:tags], using: :gin)
|
||||||
|
end
|
||||||
|
end
|
|
@ -37,6 +37,78 @@ test "Create" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "PUT /api/pleroma/admin/users/tag" do
|
||||||
|
setup do
|
||||||
|
admin = insert(:user, info: %{is_admin: true})
|
||||||
|
user1 = insert(:user, %{tags: ["x"]})
|
||||||
|
user2 = insert(:user, %{tags: ["y"]})
|
||||||
|
user3 = insert(:user, %{tags: ["unchanged"]})
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> put_req_header("accept", "application/json")
|
||||||
|
|> put(
|
||||||
|
"/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=#{
|
||||||
|
user2.nickname
|
||||||
|
}&tags[]=foo&tags[]=bar"
|
||||||
|
)
|
||||||
|
|
||||||
|
%{conn: conn, user1: user1, user2: user2, user3: user3}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it appends specified tags to users with specified nicknames", %{
|
||||||
|
conn: conn,
|
||||||
|
user1: user1,
|
||||||
|
user2: user2
|
||||||
|
} do
|
||||||
|
assert json_response(conn, :no_content)
|
||||||
|
assert Repo.get(User, user1.id).tags == ["x", "foo", "bar"]
|
||||||
|
assert Repo.get(User, user2.id).tags == ["y", "foo", "bar"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
|
||||||
|
assert json_response(conn, :no_content)
|
||||||
|
assert Repo.get(User, user3.id).tags == ["unchanged"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "DELETE /api/pleroma/admin/users/tag" do
|
||||||
|
setup do
|
||||||
|
admin = insert(:user, info: %{is_admin: true})
|
||||||
|
user1 = insert(:user, %{tags: ["x"]})
|
||||||
|
user2 = insert(:user, %{tags: ["y", "z"]})
|
||||||
|
user3 = insert(:user, %{tags: ["unchanged"]})
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> put_req_header("accept", "application/json")
|
||||||
|
|> delete(
|
||||||
|
"/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=#{
|
||||||
|
user2.nickname
|
||||||
|
}&tags[]=x&tags[]=z"
|
||||||
|
)
|
||||||
|
|
||||||
|
%{conn: conn, user1: user1, user2: user2, user3: user3}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it removes specified tags from users with specified nicknames", %{
|
||||||
|
conn: conn,
|
||||||
|
user1: user1,
|
||||||
|
user2: user2
|
||||||
|
} do
|
||||||
|
assert json_response(conn, :no_content)
|
||||||
|
assert Repo.get(User, user1.id).tags == []
|
||||||
|
assert Repo.get(User, user2.id).tags == ["y"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
|
||||||
|
assert json_response(conn, :no_content)
|
||||||
|
assert Repo.get(User, user3.id).tags == ["unchanged"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "/api/pleroma/admin/permission_group" do
|
describe "/api/pleroma/admin/permission_group" do
|
||||||
test "GET is giving user_info" do
|
test "GET is giving user_info" do
|
||||||
admin = insert(:user, info: %{is_admin: true})
|
admin = insert(:user, info: %{is_admin: true})
|
||||||
|
|
|
@ -54,7 +54,8 @@ test "Represent a user account" do
|
||||||
note: "",
|
note: "",
|
||||||
privacy: "public",
|
privacy: "public",
|
||||||
sensitive: false
|
sensitive: false
|
||||||
}
|
},
|
||||||
|
pleroma: %{tags: []}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == AccountView.render("account.json", %{user: user})
|
assert expected == AccountView.render("account.json", %{user: user})
|
||||||
|
@ -91,7 +92,8 @@ test "Represent a Service(bot) account" do
|
||||||
note: "",
|
note: "",
|
||||||
privacy: "public",
|
privacy: "public",
|
||||||
sensitive: false
|
sensitive: false
|
||||||
}
|
},
|
||||||
|
pleroma: %{tags: []}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == AccountView.render("account.json", %{user: user})
|
assert expected == AccountView.render("account.json", %{user: user})
|
||||||
|
|
|
@ -96,7 +96,8 @@ test "A user" do
|
||||||
"locked" => false,
|
"locked" => false,
|
||||||
"default_scope" => "public",
|
"default_scope" => "public",
|
||||||
"no_rich_text" => false,
|
"no_rich_text" => false,
|
||||||
"fields" => []
|
"fields" => [],
|
||||||
|
"pleroma" => %{"tags" => []}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: user})
|
assert represented == UserView.render("show.json", %{user: user})
|
||||||
|
@ -137,7 +138,8 @@ test "A user for a given other follower", %{user: user} do
|
||||||
"locked" => false,
|
"locked" => false,
|
||||||
"default_scope" => "public",
|
"default_scope" => "public",
|
||||||
"no_rich_text" => false,
|
"no_rich_text" => false,
|
||||||
"fields" => []
|
"fields" => [],
|
||||||
|
"pleroma" => %{"tags" => []}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: user, for: follower})
|
assert represented == UserView.render("show.json", %{user: user, for: follower})
|
||||||
|
@ -179,7 +181,8 @@ test "A user that follows you", %{user: user} do
|
||||||
"locked" => false,
|
"locked" => false,
|
||||||
"default_scope" => "public",
|
"default_scope" => "public",
|
||||||
"no_rich_text" => false,
|
"no_rich_text" => false,
|
||||||
"fields" => []
|
"fields" => [],
|
||||||
|
"pleroma" => %{"tags" => []}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: follower, for: user})
|
assert represented == UserView.render("show.json", %{user: follower, for: user})
|
||||||
|
@ -228,7 +231,8 @@ test "A blocked user for the blocker" do
|
||||||
"locked" => false,
|
"locked" => false,
|
||||||
"default_scope" => "public",
|
"default_scope" => "public",
|
||||||
"no_rich_text" => false,
|
"no_rich_text" => false,
|
||||||
"fields" => []
|
"fields" => [],
|
||||||
|
"pleroma" => %{"tags" => []}
|
||||||
}
|
}
|
||||||
|
|
||||||
blocker = Repo.get(User, blocker.id)
|
blocker = Repo.get(User, blocker.id)
|
||||||
|
|
Loading…
Reference in New Issue