From: marcin mikołajczak Date: Sun, 21 Nov 2021 15:53:30 +0000 (+0100) Subject: MastoAPI: Add user notes on accounts X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=40414bf177c93b39d75c6091ef0ce1db093edb6f;p=akkoma MastoAPI: Add user notes on accounts Signed-off-by: marcin mikołajczak --- diff --git a/docs/development/API/pleroma_api.md b/docs/development/API/pleroma_api.md index 8f6422da0..b401a7cc7 100644 --- a/docs/development/API/pleroma_api.md +++ b/docs/development/API/pleroma_api.md @@ -162,7 +162,8 @@ See [Admin-API](admin_api.md) "requested": false, "domain_blocking": false, "showing_reblogs": true, - "endorsed": false + "endorsed": false, + "note": "" } ``` @@ -186,7 +187,8 @@ See [Admin-API](admin_api.md) "requested": false, "domain_blocking": false, "showing_reblogs": true, - "endorsed": false + "endorsed": false, + "note": "" } ``` diff --git a/lib/pleroma/user_note.ex b/lib/pleroma/user_note.ex new file mode 100644 index 000000000..5e82d359f --- /dev/null +++ b/lib/pleroma/user_note.ex @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.UserNote do + use Ecto.Schema + + import Ecto.Changeset + import Ecto.Query + + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.UserNote + + schema "user_notes" do + belongs_to(:source, User, type: FlakeId.Ecto.CompatType) + belongs_to(:target, User, type: FlakeId.Ecto.CompatType) + field(:comment, :string) + + timestamps() + end + + def changeset(%UserNote{} = user_note, params \\ %{}) do + user_note + |> cast(params, [:source_id, :target_id, :comment]) + |> validate_required([:source_id, :target_id]) + end + + def show(%User{} = source, %User{} = target) do + with %UserNote{} = note <- + UserNote + |> where(source_id: ^source.id, target_id: ^target.id) + |> Repo.one() do + note.comment + else + _ -> "" + end + end + + def create(%User{} = source, %User{} = target, comment) do + %UserNote{} + |> changeset(%{ + source_id: source.id, + target_id: target.id, + comment: comment + }) + |> Repo.insert( + on_conflict: {:replace, [:comment]}, + conflict_target: [:source_id, :target_id] + ) + end +end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 54e5ebc76..6bec9f178 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -328,6 +328,29 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do } end + def note_operation do + %Operation{ + tags: ["Account actions"], + summary: "Create note", + operationId: "AccountController.note", + security: [%{"oAuth" => ["follow", "write:accounts"]}], + requestBody: request_body("Parameters", note_request()), + description: "Create a note for the given account.", + parameters: [ + %Reference{"$ref": "#/components/parameters/accountIdOrNickname"}, + Operation.parameter( + :comment, + :query, + %Schema{type: :string}, + "Account note body" + ) + ], + responses: %{ + 200 => Operation.response("Relationship", "application/json", AccountRelationship) + } + } + end + def follow_by_uri_operation do %Operation{ tags: ["Account actions"], @@ -685,6 +708,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do "blocked_by" => true, "muting" => false, "muting_notifications" => false, + "note" => "", "requested" => false, "domain_blocking" => false, "subscribing" => false, @@ -699,6 +723,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do "blocked_by" => true, "muting" => true, "muting_notifications" => false, + "note" => "", "requested" => true, "domain_blocking" => false, "subscribing" => false, @@ -713,6 +738,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do "blocked_by" => false, "muting" => true, "muting_notifications" => false, + "note" => "", "requested" => false, "domain_blocking" => true, "subscribing" => true, @@ -760,6 +786,23 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do } end + defp note_request do + %Schema{ + title: "AccountNoteRequest", + description: "POST body for adding anote for an account", + type: :object, + properties: %{ + comment: %Schema{ + type: :string, + description: "Account note body", + } + }, + example: %{ + "comment" => "Example note" + } + } + end + defp array_of_lists do %Schema{ title: "ArrayOfLists", diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index bd7143ab9..e0bd2728b 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -194,6 +194,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do "id" => "9tKi3esbG7OQgZ2920", "muting" => false, "muting_notifications" => false, + "note" => "", "requested" => false, "showing_reblogs" => true, "subscribing" => false diff --git a/lib/pleroma/web/api_spec/schemas/account_relationship.ex b/lib/pleroma/web/api_spec/schemas/account_relationship.ex index 16b73ebb4..163066032 100644 --- a/lib/pleroma/web/api_spec/schemas/account_relationship.ex +++ b/lib/pleroma/web/api_spec/schemas/account_relationship.ex @@ -22,6 +22,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountRelationship do id: FlakeID, muting: %Schema{type: :boolean}, muting_notifications: %Schema{type: :boolean}, + note: %Schema{type: :string}, requested: %Schema{type: :boolean}, showing_reblogs: %Schema{type: :boolean}, subscribing: %Schema{type: :boolean} @@ -36,6 +37,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountRelationship do "id" => "9tKi3esbG7OQgZ2920", "muting" => false, "muting_notifications" => false, + "note" => "", "requested" => false, "showing_reblogs" => true, "subscribing" => false diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex index 3d042dc19..60801f322 100644 --- a/lib/pleroma/web/api_spec/schemas/status.ex +++ b/lib/pleroma/web/api_spec/schemas/status.ex @@ -282,6 +282,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do "id" => "9toJCsKN7SmSf3aj5c", "muting" => false, "muting_notifications" => false, + "note" => "", "requested" => false, "showing_reblogs" => true, "subscribing" => false diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 5fcbffc34..8a43d49d3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -15,6 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do alias Pleroma.Maps alias Pleroma.User + alias Pleroma.UserNote alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.Pipeline @@ -53,7 +54,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do when action in [:verify_credentials, :endorsements, :identity_proofs] ) - plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action == :update_credentials) + plug( + OAuthScopesPlug, + %{scopes: ["write:accounts"]} + when action in [:update_credentials, :note] + ) plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :lists) @@ -79,7 +84,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action in [:mute, :unmute]) @relationship_actions [:follow, :unfollow] - @needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a + @needs_account ~W(followers following lists follow unfollow mute unmute block unblock note)a plug( RateLimiter, @@ -435,6 +440,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do end end + @doc "POST /api/v1/accounts/:id/note" + def note(%{assigns: %{user: noter, account: target}, body_params: %{comment: comment}} = conn, _params) do + with {:ok, _user_note} <- UserNote.create(noter, target, comment) do + render(conn, "relationship.json", user: noter, target: target) + else + {:error, message} -> json_response(conn, :forbidden, %{error: message}) + end + end + @doc "POST /api/v1/follows" def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do case User.get_cached_by_nickname(uri) do diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 9e9de33f6..a3a9f9548 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do alias Pleroma.FollowingRelationship alias Pleroma.User + alias Pleroma.UserNote alias Pleroma.UserRelationship alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MastodonAPI.AccountView @@ -156,7 +157,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do target, &User.muting_reblogs?(&1, &2) ), - endorsed: false + endorsed: false, + note: + UserNote.show( + reading_user, + target + ) } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index abb332ec2..ca5db8ea3 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -456,6 +456,7 @@ defmodule Pleroma.Web.Router do post("/accounts/:id/unblock", AccountController, :unblock) post("/accounts/:id/mute", AccountController, :mute) post("/accounts/:id/unmute", AccountController, :unmute) + post("/accounts/:id/note", AccountController, :note) get("/conversations", ConversationController, :index) post("/conversations/:id/read", ConversationController, :mark_as_read) diff --git a/priv/repo/migrations/20211121000000_create_user_notes.exs b/priv/repo/migrations/20211121000000_create_user_notes.exs new file mode 100644 index 000000000..8fc23749f --- /dev/null +++ b/priv/repo/migrations/20211121000000_create_user_notes.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.CreateUserNotes do + use Ecto.Migration + + def change do + create_if_not_exists table(:user_notes) do + add(:source_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:target_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:comment, :string) + + timestamps() + end + + create_if_not_exists( + unique_index(:user_notes, [:source_id, :target_id]) + ) + end +end diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index a92a58224..48e658dd2 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -1776,4 +1776,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do assert [%{"id" => ^id2}] = result end + + test "create a note on a user" do + %{conn: conn} = oauth_access(["write:accounts"]) + other_user = insert(:user) + + ret_conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/accounts/#{other_user.id}/note", %{ + "comment" => "Example note" + }) + + assert %{"note" => "Example note"} = json_response_and_validate_schema(ret_conn, 200) + end end diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 60881756d..9fe9d73bc 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -271,7 +271,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do requested: false, domain_blocking: false, showing_reblogs: true, - endorsed: false + endorsed: false, + note: "" } test "represent a relationship for the following and followed user" do