Quellcode durchsuchen

Move conversation actions to PleromaAPI.ConversationController

chore/expose-invalidation-to-adminfe
Egor Kislitsyn vor 4 Jahren
Ursprung
Commit
f3fc8b22b1
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden GPG-Schlüssel-ID: 1B49CB15B71E7805
7 geänderte Dateien mit 341 neuen und 324 gelöschten Zeilen
  1. +106
    -0
      lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex
  2. +0
    -93
      lib/pleroma/web/api_spec/operations/pleroma_operation.ex
  3. +95
    -0
      lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex
  4. +0
    -99
      lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
  5. +4
    -8
      lib/pleroma/web/router.ex
  6. +136
    -0
      test/web/pleroma_api/controllers/conversation_controller_test.exs
  7. +0
    -124
      test/web/pleroma_api/controllers/pleroma_api_controller_test.exs

+ 106
- 0
lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex Datei anzeigen

@@ -0,0 +1,106 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.ApiSpec.PleromaConversationOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Conversation
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.StatusOperation

import Pleroma.Web.ApiSpec.Helpers

def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end

def show_operation do
%Operation{
tags: ["Conversations"],
summary: "The conversation with the given ID",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
)
],
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "PleromaAPI.ConversationController.show",
responses: %{
200 => Operation.response("Conversation", "application/json", Conversation)
}
}
end

def statuses_operation do
%Operation{
tags: ["Conversations"],
summary: "Timeline for a given conversation",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
)
| pagination_params()
],
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "PleromaAPI.ConversationController.statuses",
responses: %{
200 =>
Operation.response(
"Array of Statuses",
"application/json",
StatusOperation.array_of_statuses()
)
}
}
end

def update_operation do
%Operation{
tags: ["Conversations"],
summary: "Update a conversation. Used to change the set of recipients.",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
),
Operation.parameter(
:recipients,
:query,
%Schema{type: :array, items: FlakeID},
"A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.",
required: true
)
],
security: [%{"oAuth" => ["write:conversations"]}],
operationId: "PleromaAPI.ConversationController.update",
responses: %{
200 => Operation.response("Conversation", "application/json", Conversation)
}
}
end

def mark_as_read_operation do
%Operation{
tags: ["Conversations"],
summary: "Marks all user's conversations as read",
security: [%{"oAuth" => ["write:conversations"]}],
operationId: "PleromaAPI.ConversationController.mark_as_read",
responses: %{
200 =>
Operation.response(
"Array of Conversations that were marked as read",
"application/json",
%Schema{
type: :array,
items: Conversation,
example: [Conversation.schema().example]
}
)
}
}
end
end

+ 0
- 93
lib/pleroma/web/api_spec/operations/pleroma_operation.ex Datei anzeigen

@@ -7,105 +7,12 @@ defmodule Pleroma.Web.ApiSpec.PleromaOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.NotificationOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.Conversation
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.StatusOperation

import Pleroma.Web.ApiSpec.Helpers

def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end

def conversation_operation do
%Operation{
tags: ["Conversations"],
summary: "The conversation with the given ID",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
)
],
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "PleromaController.conversation",
responses: %{
200 => Operation.response("Conversation", "application/json", Conversation)
}
}
end

def conversation_statuses_operation do
%Operation{
tags: ["Conversations"],
summary: "Timeline for a given conversation",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
)
| pagination_params()
],
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "PleromaController.conversation_statuses",
responses: %{
200 =>
Operation.response(
"Array of Statuses",
"application/json",
StatusOperation.array_of_statuses()
)
}
}
end

def update_conversation_operation do
%Operation{
tags: ["Conversations"],
summary: "Update a conversation. Used to change the set of recipients.",
parameters: [
Operation.parameter(:id, :path, :string, "Conversation ID",
example: "123",
required: true
),
Operation.parameter(
:recipients,
:query,
%Schema{type: :array, items: FlakeID},
"A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.",
required: true
)
],
security: [%{"oAuth" => ["write:conversations"]}],
operationId: "PleromaController.update_conversation",
responses: %{
200 => Operation.response("Conversation", "application/json", Conversation)
}
}
end

def mark_conversations_as_read_operation do
%Operation{
tags: ["Conversations"],
summary: "Marks all user's conversations as read",
security: [%{"oAuth" => ["write:conversations"]}],
operationId: "PleromaController.mark_conversations_as_read",
responses: %{
200 =>
Operation.response(
"Array of Conversations that were marked as read",
"application/json",
%Schema{
type: :array,
items: Conversation,
example: [Conversation.schema().example]
}
)
}
}
end

def mark_notifications_as_read_operation do
%Operation{
tags: ["Notifications"],


+ 95
- 0
lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex Datei anzeigen

@@ -0,0 +1,95 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.PleromaAPI.ConversationController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]

alias Pleroma.Conversation.Participation
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.MastodonAPI.StatusView

plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:put_view, Pleroma.Web.MastodonAPI.ConversationView)
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:show, :statuses])

plug(
OAuthScopesPlug,
%{scopes: ["write:conversations"]} when action in [:update, :mark_as_read]
)

defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaConversationOperation

def show(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: participation_id}) do
with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id) do
render(conn, "participation.json", participation: participation, for: user)
else
_error ->
conn
|> put_status(:not_found)
|> json(%{"error" => "Unknown conversation id"})
end
end

def statuses(
%{assigns: %{user: %{id: user_id} = user}} = conn,
%{id: participation_id} = params
) do
with %Participation{user_id: ^user_id} = participation <-
Participation.get(participation_id, preload: [:conversation]) do
params =
params
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("blocking_user", user)
|> Map.put("muting_user", user)
|> Map.put("user", user)

activities =
participation.conversation.ap_id
|> ActivityPub.fetch_activities_for_context_query(params)
|> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|> Enum.reverse()

conn
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("index.json", activities: activities, for: user, as: :activity)
else
_error ->
conn
|> put_status(:not_found)
|> json(%{"error" => "Unknown conversation id"})
end
end

def update(
%{assigns: %{user: %{id: user_id} = user}} = conn,
%{id: participation_id, recipients: recipients}
) do
with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id),
{:ok, participation} <- Participation.set_recipients(participation, recipients) do
render(conn, "participation.json", participation: participation, for: user)
else
{:error, message} ->
conn
|> put_status(:bad_request)
|> json(%{"error" => message})

_error ->
conn
|> put_status(:not_found)
|> json(%{"error" => "Unknown conversation id"})
end
end

def mark_as_read(%{assigns: %{user: user}} = conn, _params) do
with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
conn
|> add_link_headers(participations)
|> render("participations.json", participations: participations, for: user)
end
end
end

+ 0
- 99
lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex Datei anzeigen

@@ -5,118 +5,19 @@
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]

alias Pleroma.Conversation.Participation
alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.MastodonAPI.ConversationView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView

plug(Pleroma.Web.ApiSpec.CastAndValidate)

plug(
OAuthScopesPlug,
%{scopes: ["read:statuses"]}
when action in [:conversation, :conversation_statuses]
)

plug(
OAuthScopesPlug,
%{scopes: ["write:conversations"]}
when action in [:update_conversation, :mark_conversations_as_read]
)

plug(
OAuthScopesPlug,
%{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
)

defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation

def conversation(%{assigns: %{user: user}} = conn, %{id: participation_id}) do
with %Participation{} = participation <- Participation.get(participation_id),
true <- user.id == participation.user_id do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
else
_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end

def conversation_statuses(
%{assigns: %{user: %{id: user_id} = user}} = conn,
%{id: participation_id} = params
) do
with %Participation{user_id: ^user_id} = participation <-
Participation.get(participation_id, preload: [:conversation]) do
params =
params
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("blocking_user", user)
|> Map.put("muting_user", user)
|> Map.put("user", user)

activities =
participation.conversation.ap_id
|> ActivityPub.fetch_activities_for_context_query(params)
|> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|> Enum.reverse()

conn
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("index.json",
activities: activities,
for: user,
as: :activity
)
else
_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end

def update_conversation(
%{assigns: %{user: user}} = conn,
%{id: participation_id, recipients: recipients}
) do
with %Participation{} = participation <- Participation.get(participation_id),
true <- user.id == participation.user_id,
{:ok, participation} <- Participation.set_recipients(participation, recipients) do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
else
{:error, message} ->
conn
|> put_status(:bad_request)
|> json(%{"error" => message})

_error ->
conn
|> put_status(404)
|> json(%{"error" => "Unknown conversation id"})
end
end

def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
conn
|> add_link_headers(participations)
|> put_view(ConversationView)
|> render("participations.json", participations: participations, for: user)
end
end

def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do
with {:ok, notification} <- Notification.read_one(user, notification_id) do
conn


+ 4
- 8
lib/pleroma/web/router.ex Datei anzeigen

@@ -305,15 +305,11 @@ defmodule Pleroma.Web.Router do
scope [] do
pipe_through(:authenticated_api)

get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses)
get("/conversations/:id", PleromaAPIController, :conversation)
post("/conversations/read", PleromaAPIController, :mark_conversations_as_read)
end

scope [] do
pipe_through(:authenticated_api)
get("/conversations/:id/statuses", ConversationController, :statuses)
get("/conversations/:id", ConversationController, :show)
post("/conversations/read", ConversationController, :mark_as_read)
patch("/conversations/:id", ConversationController, :update)

patch("/conversations/:id", PleromaAPIController, :update_conversation)
put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create)
delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete)
post("/notifications/read", PleromaAPIController, :mark_notifications_as_read)


+ 136
- 0
test/web/pleroma_api/controllers/conversation_controller_test.exs Datei anzeigen

@@ -0,0 +1,136 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do
use Pleroma.Web.ConnCase

alias Pleroma.Conversation.Participation
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI

import Pleroma.Factory

test "/api/v1/pleroma/conversations/:id" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})

[participation] = Participation.for_user(other_user)

result =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}")
|> json_response_and_validate_schema(200)

assert result["id"] == participation.id |> to_string()
end

test "/api/v1/pleroma/conversations/:id/statuses" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])
third_user = insert(:user)

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{third_user.nickname}!", visibility: "direct"})

{:ok, activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})

[participation] = Participation.for_user(other_user)

{:ok, activity_two} =
CommonAPI.post(other_user, %{
status: "Hi!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
})

result =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses")
|> json_response_and_validate_schema(200)

assert length(result) == 2

id_one = activity.id
id_two = activity_two.id
assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result

{:ok, %{id: id_three}} =
CommonAPI.post(other_user, %{
status: "Bye!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
})

assert [%{"id" => ^id_two}, %{"id" => ^id_three}] =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2")
|> json_response_and_validate_schema(:ok)

assert [%{"id" => ^id_three}] =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}")
|> json_response_and_validate_schema(:ok)
end

test "PATCH /api/v1/pleroma/conversations/:id" do
%{user: user, conn: conn} = oauth_access(["write:conversations"])
other_user = insert(:user)

{:ok, _activity} = CommonAPI.post(user, %{status: "Hi", visibility: "direct"})

[participation] = Participation.for_user(user)

participation = Repo.preload(participation, :recipients)

user = User.get_cached_by_id(user.id)
assert [user] == participation.recipients
assert other_user not in participation.recipients

query = "recipients[]=#{user.id}&recipients[]=#{other_user.id}"

result =
conn
|> patch("/api/v1/pleroma/conversations/#{participation.id}?#{query}")
|> json_response_and_validate_schema(200)

assert result["id"] == participation.id |> to_string

[participation] = Participation.for_user(user)
participation = Repo.preload(participation, :recipients)

assert user in participation.recipients
assert other_user in participation.recipients
end

test "POST /api/v1/pleroma/conversations/read" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["write:conversations"])

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})

[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == false
assert Participation.get(participation1.id).read == false
assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2

[%{"unread" => false}, %{"unread" => false}] =
conn
|> post("/api/v1/pleroma/conversations/read", %{})
|> json_response_and_validate_schema(200)

[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == true
assert Participation.get(participation1.id).read == true
assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0
end
end

+ 0
- 124
test/web/pleroma_api/controllers/pleroma_api_controller_test.exs Datei anzeigen

@@ -5,136 +5,12 @@
defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do
use Pleroma.Web.ConnCase

alias Pleroma.Conversation.Participation
alias Pleroma.Notification
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI

import Pleroma.Factory

test "/api/v1/pleroma/conversations/:id" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})

[participation] = Participation.for_user(other_user)

result =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}")
|> json_response_and_validate_schema(200)

assert result["id"] == participation.id |> to_string()
end

test "/api/v1/pleroma/conversations/:id/statuses" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["read:statuses"])
third_user = insert(:user)

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{third_user.nickname}!", visibility: "direct"})

{:ok, activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})

[participation] = Participation.for_user(other_user)

{:ok, activity_two} =
CommonAPI.post(other_user, %{
status: "Hi!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
})

result =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses")
|> json_response_and_validate_schema(200)

assert length(result) == 2

id_one = activity.id
id_two = activity_two.id
assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result

{:ok, %{id: id_three}} =
CommonAPI.post(other_user, %{
status: "Bye!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
})

assert [%{"id" => ^id_two}, %{"id" => ^id_three}] =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2")
|> json_response_and_validate_schema(:ok)

assert [%{"id" => ^id_three}] =
conn
|> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}")
|> json_response_and_validate_schema(:ok)
end

test "PATCH /api/v1/pleroma/conversations/:id" do
%{user: user, conn: conn} = oauth_access(["write:conversations"])
other_user = insert(:user)

{:ok, _activity} = CommonAPI.post(user, %{status: "Hi", visibility: "direct"})

[participation] = Participation.for_user(user)

participation = Repo.preload(participation, :recipients)

user = User.get_cached_by_id(user.id)
assert [user] == participation.recipients
assert other_user not in participation.recipients

query = "recipients[]=#{user.id}&recipients[]=#{other_user.id}"

result =
conn
|> patch("/api/v1/pleroma/conversations/#{participation.id}?#{query}")
|> json_response_and_validate_schema(200)

assert result["id"] == participation.id |> to_string

[participation] = Participation.for_user(user)
participation = Repo.preload(participation, :recipients)

assert user in participation.recipients
assert other_user in participation.recipients
end

test "POST /api/v1/pleroma/conversations/read" do
user = insert(:user)
%{user: other_user, conn: conn} = oauth_access(["write:conversations"])

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})

{:ok, _activity} =
CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})

[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == false
assert Participation.get(participation1.id).read == false
assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2

[%{"unread" => false}, %{"unread" => false}] =
conn
|> post("/api/v1/pleroma/conversations/read", %{})
|> json_response_and_validate_schema(200)

[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == true
assert Participation.get(participation1.id).read == true
assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0
end

describe "POST /api/v1/pleroma/notifications/read" do
setup do: oauth_access(["write:notifications"])



Laden…
Abbrechen
Speichern