Merge branch 'feature/mastodon_api_2.4.x' into 'develop'

Add/Fix Mastodon endpoints for 2.4.3 compatibility

See merge request pleroma/pleroma!266
This commit is contained in:
kaniini 2018-09-03 12:33:36 +00:00
commit 1c9e539b47
11 changed files with 435 additions and 5 deletions

62
lib/pleroma/filter.ex Normal file
View File

@ -0,0 +1,62 @@
defmodule Pleroma.Filter do
use Ecto.Schema
import Ecto.{Changeset, Query}
alias Pleroma.{User, Repo, Activity}
schema "filters" do
belongs_to(:user, Pleroma.User)
field(:filter_id, :integer)
field(:hide, :boolean, default: false)
field(:whole_word, :boolean, default: true)
field(:phrase, :string)
field(:context, {:array, :string})
field(:expires_at, :utc_datetime)
timestamps()
end
def get(id, %{id: user_id} = _user) do
query =
from(
f in Pleroma.Filter,
where: f.filter_id == ^id,
where: f.user_id == ^user_id
)
Repo.one(query)
end
def get_filters(%Pleroma.User{id: user_id} = user) do
query =
from(
f in Pleroma.Filter,
where: f.user_id == ^user_id
)
Repo.all(query)
end
def create(%Pleroma.Filter{} = filter) do
Repo.insert(filter)
end
def delete(%Pleroma.Filter{id: filter_key} = filter) when is_number(filter_key) do
Repo.delete(filter)
end
def delete(%Pleroma.Filter{id: filter_key} = filter) when is_nil(filter_key) do
%Pleroma.Filter{id: id} = get(filter.filter_id, %{id: filter.user_id})
filter
|> Map.put(:id, id)
|> Repo.delete()
end
def update(%Pleroma.Filter{} = filter) do
destination = Map.from_struct(filter)
Pleroma.Filter.get(filter.filter_id, %{id: filter.user_id})
|> cast(destination, [:phrase, :context, :hide, :expires_at, :whole_word])
|> Repo.update()
end
end

View File

@ -93,6 +93,11 @@ def stream_out(activity) do
Pleroma.Web.Streamer.stream("public:local", activity) Pleroma.Web.Streamer.stream("public:local", activity)
end end
activity.data["object"]
|> Map.get("tag", [])
|> Enum.filter(fn tag -> is_bitstring(tag) end)
|> Enum.map(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
if activity.data["object"]["attachment"] != [] do if activity.data["object"]["attachment"] != [] do
Pleroma.Web.Streamer.stream("public:media", activity) Pleroma.Web.Streamer.stream("public:media", activity)

View File

@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.{Repo, Object, Activity, User, Notification, Stats} alias Pleroma.{Repo, Object, Activity, User, Notification, Stats}
alias Pleroma.Web alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView} alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView, FilterView}
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
@ -125,7 +125,7 @@ def user(conn, %{"id" => id}) do
end end
@instance Application.get_env(:pleroma, :instance) @instance Application.get_env(:pleroma, :instance)
@mastodon_api_level "2.3.3" @mastodon_api_level "2.4.3"
def masto_instance(conn, _params) do def masto_instance(conn, _params) do
response = %{ response = %{
@ -1077,6 +1077,65 @@ def render_notification(user, %{id: id, activity: activity, inserted_at: created
end end
end end
def get_filters(%{assigns: %{user: user}} = conn, params) do
filters = Pleroma.Filter.get_filters(user)
res = FilterView.render("filters.json", filters: filters)
json(conn, res)
end
def create_filter(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context} = params
) do
query = %Pleroma.Filter{
user_id: user.id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", nil),
whole_word: Map.get(params, "boolean", true)
# expires_at
}
{:ok, response} = Pleroma.Filter.create(query)
res = FilterView.render("filter.json", filter: response)
json(conn, res)
end
def get_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id} = params) do
filter = Pleroma.Filter.get(filter_id, user)
res = FilterView.render("filter.json", filter: filter)
json(conn, res)
end
def update_filter(
%{assigns: %{user: user}} = conn,
%{"phrase" => phrase, "context" => context, "id" => filter_id} = params
) do
query = %Pleroma.Filter{
user_id: user.id,
filter_id: filter_id,
phrase: phrase,
context: context,
hide: Map.get(params, "irreversible", nil),
whole_word: Map.get(params, "boolean", true)
# expires_at
}
{:ok, response} = Pleroma.Filter.update(query)
res = FilterView.render("filter.json", filter: response)
json(conn, res)
end
def delete_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id} = params) do
query = %Pleroma.Filter{
user_id: user.id,
filter_id: filter_id
}
{:ok, response} = Pleroma.Filter.delete(query)
json(conn, %{})
end
def errors(conn, _) do def errors(conn, _) do
conn conn
|> put_status(500) |> put_status(500)

View File

@ -23,16 +23,18 @@ def connect(params, socket) do
"public:local:media", "public:local:media",
"user", "user",
"direct", "direct",
"list" "list",
"hashtag"
] <- params["stream"] do ] <- params["stream"] do
topic = if stream == "list", do: "list:#{params["list"]}", else: stream topic = if stream == "list", do: "list:#{params["list"]}", else: stream
socket_stream = if stream == "hashtag", do: "hashtag:#{params["tag"]}", else: stream
socket = socket =
socket socket
|> assign(:topic, topic) |> assign(:topic, topic)
|> assign(:user, user) |> assign(:user, user)
Pleroma.Web.Streamer.add_socket(params["stream"], socket) Pleroma.Web.Streamer.add_socket(socket_stream, socket)
{:ok, socket} {:ok, socket}
else else
_e -> :error _e -> :error

View File

@ -13,6 +13,7 @@ def render("account.json", %{user: user}) do
image = User.avatar_url(user) |> MediaProxy.url() image = User.avatar_url(user) |> MediaProxy.url()
header = User.banner_url(user) |> MediaProxy.url() header = User.banner_url(user) |> MediaProxy.url()
user_info = User.user_info(user) user_info = User.user_info(user)
bot = (user.info["source_data"]["type"] || "Person") in ["Application", "Service"]
emojis = emojis =
(user.info["source_data"]["tag"] || []) (user.info["source_data"]["tag"] || [])
@ -26,6 +27,11 @@ def render("account.json", %{user: user}) do
} }
end) end)
fields =
(user.info["source_data"]["attachment"] || [])
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
%{ %{
id: to_string(user.id), id: to_string(user.id),
username: username_from_nickname(user.nickname), username: username_from_nickname(user.nickname),
@ -43,7 +49,8 @@ def render("account.json", %{user: user}) do
header: header, header: header,
header_static: header, header_static: header,
emojis: emojis, emojis: emojis,
fields: [], fields: fields,
bot: bot,
source: %{ source: %{
note: "", note: "",
privacy: user_info.default_scope, privacy: user_info.default_scope,

View File

@ -0,0 +1,27 @@
defmodule Pleroma.Web.MastodonAPI.FilterView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.CommonAPI.Utils
def render("filters.json", %{filters: filters} = opts) do
render_many(filters, FilterView, "filter.json", opts)
end
def render("filter.json", %{filter: filter}) do
expires_at =
if filter.expires_at do
Utils.to_masto_date(filter.expires_at)
else
nil
end
%{
id: to_string(filter.filter_id),
phrase: filter.phrase,
context: filter.context,
expires_at: expires_at,
irreversible: filter.hide,
whole_word: false
}
end
end

View File

@ -154,6 +154,12 @@ def user_fetcher(username_or_email) do
post("/domain_blocks", MastodonAPIController, :block_domain) post("/domain_blocks", MastodonAPIController, :block_domain)
delete("/domain_blocks", MastodonAPIController, :unblock_domain) delete("/domain_blocks", MastodonAPIController, :unblock_domain)
get("/filters", MastodonAPIController, :get_filters)
post("/filters", MastodonAPIController, :create_filter)
get("/filters/:id", MastodonAPIController, :get_filter)
put("/filters/:id", MastodonAPIController, :update_filter)
delete("/filters/:id", MastodonAPIController, :delete_filter)
get("/suggestions", MastodonAPIController, :suggestions) get("/suggestions", MastodonAPIController, :suggestions)
end end

View File

@ -0,0 +1,20 @@
defmodule Pleroma.Repo.Migrations.CreateFilters do
use Ecto.Migration
def change do
create table(:filters) do
add :user_id, references(:users, on_delete: :delete_all)
add :filter_id, :integer
add :hide, :boolean
add :phrase, :string
add :context, {:array, :string}
add :expires_at, :datetime
add :whole_word, :boolean
timestamps()
end
create index(:filters, [:user_id])
create index(:filters, [:phrase], where: "hide = true", name: :hided_phrases_index)
end
end

85
test/filter_test.exs Normal file
View File

@ -0,0 +1,85 @@
defmodule Pleroma.FilterTest do
alias Pleroma.{User, Repo}
use Pleroma.DataCase
import Pleroma.Factory
import Ecto.Query
test "creating a filter" do
user = insert(:user)
query = %Pleroma.Filter{
user_id: user.id,
filter_id: 42,
phrase: "knights",
context: ["home"]
}
{:ok, %Pleroma.Filter{} = filter} = Pleroma.Filter.create(query)
result = Pleroma.Filter.get(filter.filter_id, user)
assert query.phrase == result.phrase
end
test "deleting a filter" do
user = insert(:user)
query = %Pleroma.Filter{
user_id: user.id,
filter_id: 0,
phrase: "knights",
context: ["home"]
}
{:ok, filter} = Pleroma.Filter.create(query)
{:ok, filter} = Pleroma.Filter.delete(query)
assert is_nil(Repo.get(Pleroma.Filter, filter.filter_id))
end
test "getting all filters by an user" do
user = insert(:user)
query_one = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "knights",
context: ["home"]
}
query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "who",
context: ["home"]
}
{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.create(query_two)
filters = Pleroma.Filter.get_filters(user)
assert filter_one in filters
assert filter_two in filters
end
test "updating a filter" do
user = insert(:user)
query_one = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "knights",
context: ["home"]
}
query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "who",
context: ["home", "timeline"]
}
{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.update(query_two)
assert filter_one != filter_two
assert filter_two.phrase == query_two.phrase
assert filter_two.context == query_two.context
end
end

View File

@ -49,6 +49,44 @@ test "Represent a user account" do
} }
], ],
fields: [], fields: [],
bot: false,
source: %{
note: "",
privacy: "public",
sensitive: "false"
}
}
assert expected == AccountView.render("account.json", %{user: user})
end
test "Represent a Service(bot) account" do
user =
insert(:user, %{
info: %{"note_count" => 5, "follower_count" => 3, "source_data" => %{"type" => "Service"}},
nickname: "shp@shitposter.club",
inserted_at: ~N[2017-08-15 15:47:06.597036]
})
expected = %{
id: to_string(user.id),
username: "shp",
acct: user.nickname,
display_name: user.name,
locked: false,
created_at: "2017-08-15T15:47:06.000Z",
followers_count: 3,
following_count: 0,
statuses_count: 5,
note: user.bio,
url: user.ap_id,
avatar: "http://localhost:4001/images/avi.png",
avatar_static: "http://localhost:4001/images/avi.png",
header: "http://localhost:4001/images/banner.png",
header_static: "http://localhost:4001/images/banner.png",
emojis: [],
fields: [],
bot: true,
source: %{ source: %{
note: "", note: "",
privacy: "public", privacy: "public",

View File

@ -263,6 +263,125 @@ test "when you didn't create it", %{conn: conn} do
end end
end end
describe "filters" do
test "creating a filter", %{conn: conn} do
user = insert(:user)
filter = %Pleroma.Filter{
phrase: "knights",
context: ["home"]
}
conn =
conn
|> assign(:user, user)
|> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
assert response = json_response(conn, 200)
assert response["phrase"] == filter.phrase
assert response["context"] == filter.context
end
test "fetching a list of filters", %{conn: conn} do
user = insert(:user)
query_one = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
phrase: "knights",
context: ["home"]
}
query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "who",
context: ["home"]
}
{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.create(query_two)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/filters")
assert response = json_response(conn, 200)
end
test "get a filter", %{conn: conn} do
user = insert(:user)
query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}
{:ok, filter} = Pleroma.Filter.create(query)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/filters/#{filter.filter_id}")
assert response = json_response(conn, 200)
end
test "update a filter", %{conn: conn} do
user = insert(:user)
query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}
{:ok, filter} = Pleroma.Filter.create(query)
new = %Pleroma.Filter{
phrase: "nii",
context: ["home"]
}
conn =
conn
|> assign(:user, user)
|> put("/api/v1/filters/#{query.filter_id}", %{
phrase: new.phrase,
context: new.context
})
assert response = json_response(conn, 200)
assert response["phrase"] == new.phrase
assert response["context"] == new.context
end
test "delete a filter", %{conn: conn} do
user = insert(:user)
query = %Pleroma.Filter{
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
}
{:ok, filter} = Pleroma.Filter.create(query)
conn =
conn
|> assign(:user, user)
|> delete("/api/v1/filters/#{filter.filter_id}")
assert response = json_response(conn, 200)
assert response == %{}
end
end
describe "lists" do describe "lists" do
test "creating a list", %{conn: conn} do test "creating a list", %{conn: conn} do
user = insert(:user) user = insert(:user)