From d7af67012f64d09bb50259188473c1c94418b3a2 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 00:06:07 -0500 Subject: Implement first pass of announcement admin api CCBUG: https://git.pleroma.social/pleroma/pleroma/-/issues/2836 CCBUG: https://git.pleroma.social/pleroma/pleroma/-/issues/1470 --- lib/pleroma/announcement.ex | 51 ++++++++++ .../controllers/announcement_controller.ex | 60 ++++++++++++ .../web/admin_api/views/announcement_view.ex | 20 ++++ .../operations/admin/announcement_operation.ex | 109 +++++++++++++++++++++ lib/pleroma/web/api_spec/schemas/announcement.ex | 22 +++++ lib/pleroma/web/router.ex | 5 + 6 files changed, 267 insertions(+) create mode 100644 lib/pleroma/announcement.ex create mode 100644 lib/pleroma/web/admin_api/controllers/announcement_controller.ex create mode 100644 lib/pleroma/web/admin_api/views/announcement_view.ex create mode 100644 lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex create mode 100644 lib/pleroma/web/api_spec/schemas/announcement.ex (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex new file mode 100644 index 000000000..8cf917c9d --- /dev/null +++ b/lib/pleroma/announcement.ex @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Announcement do + use Ecto.Schema + + import Ecto.Changeset, only: [cast: 3, validate_required: 2] + + alias Pleroma.Repo + + @type t :: %__MODULE__{} + @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} + + schema "announcements" do + field(:data, :map) + + timestamps() + end + + def change(struct, params \\ %{}) do + struct + |> cast(params, [:data]) + |> validate_required([:data]) + end + + def add(params) do + changeset = change(%__MODULE__{}, params) + + Repo.insert(changeset) + end + + def list_all do + __MODULE__ + |> Repo.all() + end + + def get_by_id(id) do + Repo.get_by(__MODULE__, id: id) + end + + def delete_by_id(id) do + with announcement when not is_nil(announcement) <- get_by_id(id), + {:ok, _} <- Repo.delete(announcement) do + :ok + else + _ -> + :error + end + end +end diff --git a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex new file mode 100644 index 000000000..803408057 --- /dev/null +++ b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.AnnouncementController do + use Pleroma.Web, :controller + + alias Pleroma.Announcement + alias Pleroma.Web.ControllerHelper + alias Pleroma.Web.Plugs.OAuthScopesPlug + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:create, :delete]) + plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action in [:index, :show]) + action_fallback(Pleroma.Web.AdminAPI.FallbackController) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.AnnouncementOperation + + def index(conn, _params) do + announcements = Announcement.list_all() + + render(conn, "index.json", announcements: announcements) + end + + def show(conn, %{id: id} = _params) do + announcement = Announcement.get_by_id(id) + + if is_nil(announcement) do + {:error, :not_found} + else + render(conn, "show.json", announcement: announcement) + end + end + + def create(%{body_params: %{content: content}} = conn, _params) do + add_params = %{ + data: %{ + "content" => content + } + } + + with {:ok, announcement} <- Announcement.add(add_params) do + render(conn, "show.json", announcement: announcement) + else + _ -> + {:error, 400} + end + end + + def delete(conn, %{id: id} = _params) do + case Announcement.delete_by_id(id) do + :ok -> + conn + |> ControllerHelper.json_response(:ok, %{}) + + _ -> + {:error, :not_found} + end + end +end diff --git a/lib/pleroma/web/admin_api/views/announcement_view.ex b/lib/pleroma/web/admin_api/views/announcement_view.ex new file mode 100644 index 000000000..5ad9a454a --- /dev/null +++ b/lib/pleroma/web/admin_api/views/announcement_view.ex @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.AnnouncementView do + use Pleroma.Web, :view + + def render("index.json", %{announcements: announcements}) do + render_many(announcements, __MODULE__, "show.json") + end + + def render("show.json", %{announcement: announcement}) do + %{ + id: announcement.id, + content: announcement.data["content"], + published_at: announcement.inserted_at, + updated_at: announcement.updated_at + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex new file mode 100644 index 000000000..e4212dd06 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex @@ -0,0 +1,109 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.Announcement + alias Pleroma.Web.ApiSpec.Schemas.ApiError + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def index_operation do + %Operation{ + tags: ["Announcement managment"], + summary: "Retrieve a list of announcements", + operationId: "AdminAPI.AnnouncementController.index", + security: [%{"oAuth" => ["admin:read"]}], + responses: %{ + 200 => Operation.response("Response", "application/json", list_of_announcements()), + 403 => Operation.response("Forbidden", "application/json", ApiError) + } + } + end + + def show_operation do + %Operation{ + tags: ["Announcement managment"], + summary: "Display one announcement", + operationId: "AdminAPI.AnnouncementController.show", + security: [%{"oAuth" => ["admin:read"]}], + parameters: [ + Operation.parameter( + :id, + :path, + :string, + "announcement id" + ) + | admin_api_params() + ], + responses: %{ + 200 => Operation.response("Response", "application/json", Announcement), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def delete_operation do + %Operation{ + tags: ["Announcement managment"], + summary: "Delete one announcement", + operationId: "AdminAPI.AnnouncementController.delete", + security: [%{"oAuth" => ["admin:write"]}], + parameters: [ + Operation.parameter( + :id, + :path, + :string, + "announcement id" + ) + | admin_api_params() + ], + responses: %{ + 200 => Operation.response("Response", "application/json", %Schema{type: :object}), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def create_operation do + %Operation{ + tags: ["Announcement managment"], + summary: "Create one announcement", + operationId: "AdminAPI.AnnouncementController.create", + security: [%{"oAuth" => ["admin:write"]}], + requestBody: request_body("Parameters", create_request(), required: true), + responses: %{ + 200 => Operation.response("Response", "application/json", Announcement), + 400 => Operation.response("Bad Request", "application/json", ApiError), + 403 => Operation.response("Forbidden", "application/json", ApiError) + } + } + end + + def create_request do + %Schema{ + title: "AnnouncementCreateRequest", + type: :object, + required: [:content], + properties: %{ + content: %Schema{type: :string} + } + } + end + + def list_of_announcements do + %Schema{ + type: :array, + items: Announcement + } + end +end diff --git a/lib/pleroma/web/api_spec/schemas/announcement.ex b/lib/pleroma/web/api_spec/schemas/announcement.ex new file mode 100644 index 000000000..26f93c730 --- /dev/null +++ b/lib/pleroma/web/api_spec/schemas/announcement.ex @@ -0,0 +1,22 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.Schemas.Announcement do + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.FlakeID + + require OpenApiSpex + + OpenApiSpex.schema(%{ + title: "Account", + description: "Response schema for an account", + type: :object, + properties: %{ + id: FlakeID, + content: %Schema{type: :string}, + published_at: %Schema{type: :string, format: "date-time"}, + updated_at: %Schema{type: :string, format: "date-time"} + } + }) +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ceb6c3cfd..e63c51943 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -229,6 +229,11 @@ defmodule Pleroma.Web.Router do post("/frontends/install", FrontendController, :install) post("/backups", AdminAPIController, :create_backup) + + get("/announcements", AnnouncementController, :index) + post("/announcements", AnnouncementController, :create) + get("/announcements/:id", AnnouncementController, :show) + delete("/announcements/:id", AnnouncementController, :delete) end # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) -- cgit v1.2.3 From c867d232505189d907e72d7501817e8a1f287f1c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 09:35:35 -0500 Subject: Fill properties of announcements from Mastodon API spec --- lib/pleroma/announcement.ex | 32 ++++++++++++++++++++++ .../web/admin_api/views/announcement_view.ex | 7 +---- lib/pleroma/web/api_spec/schemas/announcement.ex | 19 +++++++++++-- 3 files changed, 49 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index 8cf917c9d..968136d16 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -48,4 +48,36 @@ defmodule Pleroma.Announcement do :error end end + + def read_by?(_announcement, _user) do + false + end + + def render_json(announcement, opts \\ []) do + extra_params = + case Keyword.fetch(opts, :for) do + {:ok, user} -> + %{read: read_by?(announcement, user)} + _ -> + %{} + end + + base = %{ + id: announcement.id, + content: announcement.data["content"], + starts_at: :null, + ends_at: :null, + all_day: false, + published_at: announcement.inserted_at, + updated_at: announcement.updated_at, + mentions: [], + statuses: [], + tags: [], + emojis: [], + reactions: [] + } + + base + |> Map.merge(extra_params) + end end diff --git a/lib/pleroma/web/admin_api/views/announcement_view.ex b/lib/pleroma/web/admin_api/views/announcement_view.ex index 5ad9a454a..8fbdc338a 100644 --- a/lib/pleroma/web/admin_api/views/announcement_view.ex +++ b/lib/pleroma/web/admin_api/views/announcement_view.ex @@ -10,11 +10,6 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementView do end def render("show.json", %{announcement: announcement}) do - %{ - id: announcement.id, - content: announcement.data["content"], - published_at: announcement.inserted_at, - updated_at: announcement.updated_at - } + Pleroma.Announcement.render_json(announcement) end end diff --git a/lib/pleroma/web/api_spec/schemas/announcement.ex b/lib/pleroma/web/api_spec/schemas/announcement.ex index 26f93c730..433437aac 100644 --- a/lib/pleroma/web/api_spec/schemas/announcement.ex +++ b/lib/pleroma/web/api_spec/schemas/announcement.ex @@ -9,14 +9,27 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Announcement do require OpenApiSpex OpenApiSpex.schema(%{ - title: "Account", - description: "Response schema for an account", + title: "Announcement", + description: "Response schema for an announcement", type: :object, properties: %{ id: FlakeID, content: %Schema{type: :string}, + starts_at: %Schema{ + oneOf: [%Schema{type: :null}, %Schema{type: :string, format: "date-time"}] + }, + ends_at: %Schema{ + oneOf: [%Schema{type: :null}, %Schema{type: :string, format: "date-time"}] + }, + all_day: %Schema{type: :boolean}, published_at: %Schema{type: :string, format: "date-time"}, - updated_at: %Schema{type: :string, format: "date-time"} + updated_at: %Schema{type: :string, format: "date-time"}, + read: %Schema{type: :boolean}, + mentions: %Schema{type: :array}, + statuses: %Schema{type: :array}, + tags: %Schema{type: :array}, + emojis: %Schema{type: :array}, + reactions: %Schema{type: :array} } }) end -- cgit v1.2.3 From 5169ad8f143d613f3fa179f88e2be6a16445df41 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 12:07:21 -0500 Subject: Implement announcement read relationships --- lib/pleroma/announcement.ex | 12 +++- lib/pleroma/announcement_read_relationship.ex | 55 ++++++++++++++++ .../api_spec/operations/announcement_operation.ex | 77 ++++++++++++++++++++++ .../controllers/announcement_controller.ex | 61 +++++++++++++++++ .../web/mastodon_api/views/announcement_view.ex | 15 +++++ lib/pleroma/web/router.ex | 5 ++ 6 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 lib/pleroma/announcement_read_relationship.ex create mode 100644 lib/pleroma/web/api_spec/operations/announcement_operation.ex create mode 100644 lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex create mode 100644 lib/pleroma/web/mastodon_api/views/announcement_view.ex (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index 968136d16..b0e787fe0 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Announcement do import Ecto.Changeset, only: [cast: 3, validate_required: 2] + alias Pleroma.AnnouncementReadRelationship alias Pleroma.Repo @type t :: %__MODULE__{} @@ -49,15 +50,20 @@ defmodule Pleroma.Announcement do end end - def read_by?(_announcement, _user) do - false + def read_by?(announcement, user) do + AnnouncementReadRelationship.exists?(user, announcement) + end + + def mark_read_by(announcement, user) do + AnnouncementReadRelationship.mark_read(user, announcement) end def render_json(announcement, opts \\ []) do extra_params = case Keyword.fetch(opts, :for) do - {:ok, user} -> + {:ok, user} when not is_nil(user) -> %{read: read_by?(announcement, user)} + _ -> %{} end diff --git a/lib/pleroma/announcement_read_relationship.ex b/lib/pleroma/announcement_read_relationship.ex new file mode 100644 index 000000000..9b64404ce --- /dev/null +++ b/lib/pleroma/announcement_read_relationship.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.AnnouncementReadRelationship do + use Ecto.Schema + + import Ecto.Changeset + + alias FlakeId.Ecto.CompatType + alias Pleroma.Announcement + alias Pleroma.Repo + alias Pleroma.User + + @type t :: %__MODULE__{} + + schema "announcement_read_relationships" do + belongs_to(:user, User, type: CompatType) + belongs_to(:announcement, Announcement, type: CompatType) + + timestamps(updated_at: false) + end + + def mark_read(user, announcement) do + %__MODULE__{} + |> cast(%{user_id: user.id, announcement_id: announcement.id}, [:user_id, :announcement_id]) + |> validate_required([:user_id, :announcement_id]) + |> foreign_key_constraint(:user_id) + |> foreign_key_constraint(:announcement_id) + |> unique_constraint([:user_id, :announcement_id]) + |> Repo.insert() + end + + def mark_unread(user, announcement) do + with relationship <- get(user, announcement), + {:exists, true} <- {:exists, not is_nil(relationship)}, + {:ok, _} <- Repo.delete(relationship) do + :ok + else + {:exists, false} -> + :ok + + _ -> + :error + end + end + + def get(user, announcement) do + Repo.get_by(__MODULE__, user_id: user.id, announcement_id: announcement.id) + end + + def exists?(user, announcement) do + not is_nil(get(user, announcement)) + end +end diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex new file mode 100644 index 000000000..f99b0c263 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex @@ -0,0 +1,77 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.Announcement + alias Pleroma.Web.ApiSpec.Schemas.ApiError + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def index_operation do + %Operation{ + tags: ["Announcement"], + summary: "Retrieve a list of announcements", + operationId: "MastodonAPI.AnnouncementController.index", + responses: %{ + 200 => Operation.response("Response", "application/json", list_of_announcements()), + 403 => Operation.response("Forbidden", "application/json", ApiError) + } + } + end + + def show_operation do + %Operation{ + tags: ["Announcement"], + summary: "Display one announcement", + operationId: "MastodonAPI.AnnouncementController.show", + parameters: [ + Operation.parameter( + :id, + :path, + :string, + "announcement id" + ) + ], + responses: %{ + 200 => Operation.response("Response", "application/json", Announcement), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def mark_read_operation do + %Operation{ + tags: ["Announcement"], + summary: "Mark one announcement as read", + operationId: "MastodonAPI.AnnouncementController.mark_read", + security: [%{"oAuth" => ["write:accounts"]}], + parameters: [ + Operation.parameter( + :id, + :path, + :string, + "announcement id" + ) + ], + responses: %{ + 200 => Operation.response("Response", "application/json", Announcement), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def list_of_announcements do + %Schema{ + type: :array, + items: Announcement + } + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex new file mode 100644 index 000000000..e5fcd3066 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AnnouncementController do + use Pleroma.Web, :controller + + # import Pleroma.Web.ControllerHelper, + # only: [ + # json_response: 3 + # ] + + alias Pleroma.Announcement + alias Pleroma.Web.Plugs.OAuthScopesPlug + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + + # MastodonAPI specs do not have oauth requirements for showing + # announcements, but we have "private instance" options. When that + # is set, require read:accounts scope, symmetric to write:accounts + # for `mark_read`. + plug( + OAuthScopesPlug, + %{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]} + when action in [:show, :index] + ) + + # Same as in MastodonAPI specs + plug( + OAuthScopesPlug, + %{fallback: :proceed_unauthenticated, scopes: ["write:accounts"]} + when action in [:mark_read] + ) + + action_fallback(Pleroma.Web.MastodonAPI.FallbackController) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AnnouncementOperation + + @doc "GET /api/v1/announcements" + def index(%{assigns: %{user: user}} = conn, _params) do + render(conn, "index.json", announcements: all_visible(), user: user) + end + + def index(conn, _params) do + render(conn, "index.json", announcements: all_visible(), user: nil) + end + + defp all_visible do + Announcement.list_all() + end + + @doc "POST /api/v1/announcements/:id/dismiss" + def mark_read(_conn, _params) do + {:error, :not_found} + end + + @doc "POST /api/v1/announcements/:id" + def show(_conn, _params) do + {:error, :not_found} + end +end diff --git a/lib/pleroma/web/mastodon_api/views/announcement_view.ex b/lib/pleroma/web/mastodon_api/views/announcement_view.ex new file mode 100644 index 000000000..93fdfb1f1 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/announcement_view.ex @@ -0,0 +1,15 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MastodonAPI.AnnouncementView do + use Pleroma.Web, :view + + def render("index.json", %{announcements: announcements, user: user}) do + render_many(announcements, __MODULE__, "show.json", user: user) + end + + def render("show.json", %{announcement: announcement, user: user}) do + Pleroma.Announcement.render_json(announcement, for: user) + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e63c51943..5be9891b1 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -580,6 +580,8 @@ defmodule Pleroma.Web.Router do get("/timelines/home", TimelineController, :home) get("/timelines/direct", TimelineController, :direct) get("/timelines/list/:list_id", TimelineController, :list) + + post("/announcements/:id/dismiss", AnnouncementController, :mark_read) end scope "/api/v1", Pleroma.Web.MastodonAPI do @@ -624,6 +626,9 @@ defmodule Pleroma.Web.Router do get("/polls/:id", PollController, :show) get("/directory", DirectoryController, :index) + + get("/announcements", AnnouncementController, :index) + get("/announcements/:id", AnnouncementController, :show) end scope "/api/v2", Pleroma.Web.MastodonAPI do -- cgit v1.2.3 From aa1fff279e98c6d16095538382413d3b870cee2b Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 16:19:35 -0500 Subject: Implement GET /api/v1/announcements/:id --- .../mastodon_api/controllers/announcement_controller.ex | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index e5fcd3066..528d14adc 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -55,7 +55,20 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do end @doc "POST /api/v1/announcements/:id" - def show(_conn, _params) do - {:error, :not_found} + def show(%{assigns: %{user: user}} = conn, %{id: id} = _params) do + render_announcement_by_id(conn, id, user) + end + + def show(conn, %{id: id} = _params) do + render_announcement_by_id(conn, id) + end + + def render_announcement_by_id(conn, id, user \\ nil) do + with announcement when not is_nil(announcement) <- Announcement.get_by_id(id) do + render(conn, "show.json", announcement: announcement, user: user) + else + _ -> + {:error, :not_found} + end end end -- cgit v1.2.3 From 2b39b36e490fc1222d8f3d737cb26e62af294e03 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 16:59:20 -0500 Subject: Implement POST /api/v1/announcements/:id/dismiss --- .../web/api_spec/operations/announcement_operation.ex | 2 +- .../controllers/announcement_controller.ex | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex index f99b0c263..c33b9e135 100644 --- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex @@ -61,7 +61,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do ) ], responses: %{ - 200 => Operation.response("Response", "application/json", Announcement), + 200 => Operation.response("Response", "application/json", %Schema{type: :object}), 403 => Operation.response("Forbidden", "application/json", ApiError), 404 => Operation.response("Not Found", "application/json", ApiError) } diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index 528d14adc..c51c38d5e 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -5,10 +5,10 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do use Pleroma.Web, :controller - # import Pleroma.Web.ControllerHelper, - # only: [ - # json_response: 3 - # ] + import Pleroma.Web.ControllerHelper, + only: [ + json_response: 3 + ] alias Pleroma.Announcement alias Pleroma.Web.Plugs.OAuthScopesPlug @@ -50,8 +50,14 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do end @doc "POST /api/v1/announcements/:id/dismiss" - def mark_read(_conn, _params) do - {:error, :not_found} + def mark_read(%{assigns: %{user: user}} = conn, %{id: id} = _params) do + with announcement when not is_nil(announcement) <- Announcement.get_by_id(id), + {:ok, _} <- Announcement.mark_read_by(announcement, user) do + json_response(conn, :ok, %{}) + else + _ -> + {:error, :not_found} + end end @doc "POST /api/v1/announcements/:id" -- cgit v1.2.3 From 009817c9ee95f131d6a06e52c06c662ec95a38d4 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 17:00:49 -0500 Subject: Correct docstring for AnnouncementController.show --- lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index c51c38d5e..f3ec78265 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -60,7 +60,7 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do end end - @doc "POST /api/v1/announcements/:id" + @doc "GET /api/v1/announcements/:id" def show(%{assigns: %{user: user}} = conn, %{id: id} = _params) do render_announcement_by_id(conn, id, user) end -- cgit v1.2.3 From fcf3c9057ec1c49a0c9a400985c1dde4a5d7e9db Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 18:21:20 -0500 Subject: Implement visibility filtering for announcements --- lib/pleroma/announcement.ex | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index b0e787fe0..b3c88b441 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Announcement do use Ecto.Schema import Ecto.Changeset, only: [cast: 3, validate_required: 2] + import Ecto.Query alias Pleroma.AnnouncementReadRelationship alias Pleroma.Repo @@ -15,16 +16,36 @@ defmodule Pleroma.Announcement do schema "announcements" do field(:data, :map) + field(:starts_at, :naive_datetime) + field(:ends_at, :naive_datetime) timestamps() end def change(struct, params \\ %{}) do struct + |> validate_params() |> cast(params, [:data]) |> validate_required([:data]) end + defp validate_params(params) do + base_struct = %{ + "content" => "", + "all_day" => false + } + + merged_data = + Map.merge(base_struct, params.data) + |> Map.take(["content", "all_day"]) + + %{ + data: merged_data, + starts_at: Map.get(params, "starts_at"), + ends_at: Map.get(params, "ends_at") + } + end + def add(params) do changeset = change(%__MODULE__{}, params) @@ -86,4 +107,17 @@ defmodule Pleroma.Announcement do base |> Map.merge(extra_params) end + + # "visible" means: + # starts_at < time < ends_at + def list_all_visible_when(time) do + __MODULE__ + |> where([a], is_nil(a.starts_at) or a.starts_at < ^time) + |> where([a], is_nil(a.ends_at) or a.ends_at > ^time) + |> Repo.all() + end + + def list_all_visible do + list_all_visible_when(NaiveDateTime.utc_now()) + end end -- cgit v1.2.3 From cf8334dbc153eed7d65febb4ae4fd3c03bb106b2 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 19:12:01 -0500 Subject: Add starts_at, ends_at and all_day parameters --- lib/pleroma/announcement.ex | 16 ++++++---------- .../web/admin_api/controllers/announcement_controller.ex | 15 +++++++++------ .../api_spec/operations/admin/announcement_operation.ex | 5 ++++- lib/pleroma/web/api_spec/schemas/announcement.ex | 8 ++++++-- 4 files changed, 25 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index b3c88b441..85500751e 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -24,8 +24,7 @@ defmodule Pleroma.Announcement do def change(struct, params \\ %{}) do struct - |> validate_params() - |> cast(params, [:data]) + |> cast(validate_params(params), [:data, :starts_at, :ends_at]) |> validate_required([:data]) end @@ -39,11 +38,8 @@ defmodule Pleroma.Announcement do Map.merge(base_struct, params.data) |> Map.take(["content", "all_day"]) - %{ - data: merged_data, - starts_at: Map.get(params, "starts_at"), - ends_at: Map.get(params, "ends_at") - } + params + |> Map.merge(%{data: merged_data}) end def add(params) do @@ -92,9 +88,9 @@ defmodule Pleroma.Announcement do base = %{ id: announcement.id, content: announcement.data["content"], - starts_at: :null, - ends_at: :null, - all_day: false, + starts_at: announcement.starts_at, + ends_at: announcement.ends_at, + all_day: announcement.data["all_day"], published_at: announcement.inserted_at, updated_at: announcement.updated_at, mentions: [], diff --git a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex index 803408057..ad94e2642 100644 --- a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex @@ -32,12 +32,15 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementController do end end - def create(%{body_params: %{content: content}} = conn, _params) do - add_params = %{ - data: %{ - "content" => content - } - } + def create(%{body_params: params} = conn, _params) do + data = + %{} + |> Pleroma.Maps.put_if_present("content", params, &Map.fetch(&1, :content)) + |> Pleroma.Maps.put_if_present("all_day", params, &Map.fetch(&1, :all_day)) + + add_params = + params + |> Map.merge(%{data: data}) with {:ok, announcement} <- Announcement.add(add_params) do render(conn, "show.json", announcement: announcement) diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex index e4212dd06..8179a0e7b 100644 --- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex @@ -95,7 +95,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do type: :object, required: [:content], properties: %{ - content: %Schema{type: :string} + content: %Schema{type: :string}, + starts_at: %Schema{type: :string, format: "date-time"}, + ends_at: %Schema{type: :string, format: "date-time"}, + all_day: %Schema{type: :boolean} } } end diff --git a/lib/pleroma/web/api_spec/schemas/announcement.ex b/lib/pleroma/web/api_spec/schemas/announcement.ex index 433437aac..094fd7c68 100644 --- a/lib/pleroma/web/api_spec/schemas/announcement.ex +++ b/lib/pleroma/web/api_spec/schemas/announcement.ex @@ -16,10 +16,14 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Announcement do id: FlakeID, content: %Schema{type: :string}, starts_at: %Schema{ - oneOf: [%Schema{type: :null}, %Schema{type: :string, format: "date-time"}] + type: :string, + format: "date-time", + nullable: true }, ends_at: %Schema{ - oneOf: [%Schema{type: :null}, %Schema{type: :string, format: "date-time"}] + type: :string, + format: "date-time", + nullable: true }, all_day: %Schema{type: :boolean}, published_at: %Schema{type: :string, format: "date-time"}, -- cgit v1.2.3 From d569694ae91fa20654e5639989d3eec0ca3c8a54 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 19:17:49 -0500 Subject: Show only visible announcements in MastodonAPI --- lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index f3ec78265..a2179f934 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -46,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do end defp all_visible do - Announcement.list_all() + Announcement.list_all_visible() end @doc "POST /api/v1/announcements/:id/dismiss" -- cgit v1.2.3 From 881179ec725c3b71868fdcba983fdedd295e5125 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 19:22:28 -0500 Subject: Remove GET /api/v1/announcements/:id --- .../api_spec/operations/announcement_operation.ex | 21 --------------------- .../controllers/announcement_controller.ex | 18 ------------------ lib/pleroma/web/router.ex | 1 - 3 files changed, 40 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex index c33b9e135..a66073b8b 100644 --- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex @@ -25,27 +25,6 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do } end - def show_operation do - %Operation{ - tags: ["Announcement"], - summary: "Display one announcement", - operationId: "MastodonAPI.AnnouncementController.show", - parameters: [ - Operation.parameter( - :id, - :path, - :string, - "announcement id" - ) - ], - responses: %{ - 200 => Operation.response("Response", "application/json", Announcement), - 403 => Operation.response("Forbidden", "application/json", ApiError), - 404 => Operation.response("Not Found", "application/json", ApiError) - } - } - end - def mark_read_operation do %Operation{ tags: ["Announcement"], diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index a2179f934..e6da7892c 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -59,22 +59,4 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do {:error, :not_found} end end - - @doc "GET /api/v1/announcements/:id" - def show(%{assigns: %{user: user}} = conn, %{id: id} = _params) do - render_announcement_by_id(conn, id, user) - end - - def show(conn, %{id: id} = _params) do - render_announcement_by_id(conn, id) - end - - def render_announcement_by_id(conn, id, user \\ nil) do - with announcement when not is_nil(announcement) <- Announcement.get_by_id(id) do - render(conn, "show.json", announcement: announcement, user: user) - else - _ -> - {:error, :not_found} - end - end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 5be9891b1..51a9dec6b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -628,7 +628,6 @@ defmodule Pleroma.Web.Router do get("/directory", DirectoryController, :index) get("/announcements", AnnouncementController, :index) - get("/announcements/:id", AnnouncementController, :show) end scope "/api/v2", Pleroma.Web.MastodonAPI do -- cgit v1.2.3 From 11a1996bf5f283099fd9ecbb5c64e051ec46a5df Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 20:55:41 -0500 Subject: Implement update announcement admin api --- lib/pleroma/announcement.ex | 22 ++++++---- .../controllers/announcement_controller.ex | 29 +++++++++---- .../operations/admin/announcement_operation.ex | 49 +++++++++++++++++++--- lib/pleroma/web/router.ex | 1 + 4 files changed, 81 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index 85500751e..8c15d5bdf 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -24,18 +24,20 @@ defmodule Pleroma.Announcement do def change(struct, params \\ %{}) do struct - |> cast(validate_params(params), [:data, :starts_at, :ends_at]) + |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at]) |> validate_required([:data]) end - defp validate_params(params) do - base_struct = %{ - "content" => "", - "all_day" => false - } + defp validate_params(struct, params) do + base_data = + %{ + "content" => "", + "all_day" => false + } + |> Map.merge((struct && struct.data) || %{}) merged_data = - Map.merge(base_struct, params.data) + Map.merge(base_data, params.data) |> Map.take(["content", "all_day"]) params @@ -48,6 +50,12 @@ defmodule Pleroma.Announcement do Repo.insert(changeset) end + def update(announcement, params) do + changeset = change(announcement, params) + + Repo.update(changeset) + end + def list_all do __MODULE__ |> Repo.all() diff --git a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex index ad94e2642..6195e582a 100644 --- a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementController do alias Pleroma.Web.Plugs.OAuthScopesPlug plug(Pleroma.Web.ApiSpec.CastAndValidate) - plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:create, :delete]) + plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:create, :delete, :change]) plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action in [:index, :show]) action_fallback(Pleroma.Web.AdminAPI.FallbackController) @@ -33,18 +33,33 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementController do end def create(%{body_params: params} = conn, _params) do + with {:ok, announcement} <- Announcement.add(change_params(params)) do + render(conn, "show.json", announcement: announcement) + else + _ -> + {:error, 400} + end + end + + def change_params(orig_params) do data = %{} - |> Pleroma.Maps.put_if_present("content", params, &Map.fetch(&1, :content)) - |> Pleroma.Maps.put_if_present("all_day", params, &Map.fetch(&1, :all_day)) + |> Pleroma.Maps.put_if_present("content", orig_params, &Map.fetch(&1, :content)) + |> Pleroma.Maps.put_if_present("all_day", orig_params, &Map.fetch(&1, :all_day)) - add_params = - params - |> Map.merge(%{data: data}) + orig_params + |> Map.merge(%{data: data}) + end - with {:ok, announcement} <- Announcement.add(add_params) do + def change(%{body_params: params} = conn, %{id: id} = _params) do + with announcement <- Announcement.get_by_id(id), + {:exists, true} <- {:exists, not is_nil(announcement)}, + {:ok, announcement} <- Announcement.update(announcement, change_params(params)) do render(conn, "show.json", announcement: announcement) else + {:exists, false} -> + {:error, :not_found} + _ -> {:error, 400} end diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex index 8179a0e7b..cdf04d357 100644 --- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex @@ -89,17 +89,54 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do } end + def change_operation do + %Operation{ + tags: ["Announcement managment"], + summary: "Change one announcement", + operationId: "AdminAPI.AnnouncementController.change", + security: [%{"oAuth" => ["admin:write"]}], + parameters: [ + Operation.parameter( + :id, + :path, + :string, + "announcement id" + ) + | admin_api_params() + ], + requestBody: request_body("Parameters", change_request(), required: true), + responses: %{ + 200 => Operation.response("Response", "application/json", Announcement), + 400 => Operation.response("Bad Request", "application/json", ApiError), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + defp create_or_change_props do + %{ + content: %Schema{type: :string}, + starts_at: %Schema{type: :string, format: "date-time", nullable: true}, + ends_at: %Schema{type: :string, format: "date-time", nullable: true}, + all_day: %Schema{type: :boolean} + } + end + def create_request do %Schema{ title: "AnnouncementCreateRequest", type: :object, required: [:content], - properties: %{ - content: %Schema{type: :string}, - starts_at: %Schema{type: :string, format: "date-time"}, - ends_at: %Schema{type: :string, format: "date-time"}, - all_day: %Schema{type: :boolean} - } + properties: create_or_change_props() + } + end + + def change_request do + %Schema{ + title: "AnnouncementChangeRequest", + type: :object, + properties: create_or_change_props() } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 51a9dec6b..af56494a2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -233,6 +233,7 @@ defmodule Pleroma.Web.Router do get("/announcements", AnnouncementController, :index) post("/announcements", AnnouncementController, :create) get("/announcements/:id", AnnouncementController, :show) + patch("/announcements/:id", AnnouncementController, :change) delete("/announcements/:id", AnnouncementController, :delete) end -- cgit v1.2.3 From eb1a29640f2d7c7d3daca0626b2beb623903c9cd Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 21:26:05 -0500 Subject: Add pagination to AdminAPI.AnnouncementController.index --- lib/pleroma/announcement.ex | 7 +++++++ .../web/admin_api/controllers/announcement_controller.ex | 9 +++++++-- .../api_spec/operations/admin/announcement_operation.ex | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index 8c15d5bdf..6c11eff7e 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -61,6 +61,13 @@ defmodule Pleroma.Announcement do |> Repo.all() end + def list_paginated(%{limit: limited_number, offset: offset_number}) do + __MODULE__ + |> limit(^limited_number) + |> offset(^offset_number) + |> Repo.all() + end + def get_by_id(id) do Repo.get_by(__MODULE__, id: id) end diff --git a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex index 6195e582a..6ad5fc12c 100644 --- a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex @@ -16,8 +16,13 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementController do defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.AnnouncementOperation - def index(conn, _params) do - announcements = Announcement.list_all() + defp default_limit, do: 20 + + def index(conn, params) do + limit = Map.get(params, :limit, default_limit()) + offset = Map.get(params, :offset, 0) + + announcements = Announcement.list_paginated(%{limit: limit, offset: offset}) render(conn, "index.json", announcements: announcements) end diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex index cdf04d357..58a039e72 100644 --- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex @@ -21,8 +21,24 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do summary: "Retrieve a list of announcements", operationId: "AdminAPI.AnnouncementController.index", security: [%{"oAuth" => ["admin:read"]}], + parameters: [ + Operation.parameter( + :limit, + :query, + %Schema{type: :integer, minimum: 1}, + "the maximum number of announcements to return" + ), + Operation.parameter( + :offset, + :query, + %Schema{type: :integer, minimum: 0}, + "the offset of the first announcement to return" + ) + | admin_api_params() + ], responses: %{ 200 => Operation.response("Response", "application/json", list_of_announcements()), + 400 => Operation.response("Forbidden", "application/json", ApiError), 403 => Operation.response("Forbidden", "application/json", ApiError) } } -- cgit v1.2.3 From ebcda5265b9c82be26eae65b5ab39629a525c3fa Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 8 Mar 2022 23:00:51 -0500 Subject: Format announcements into html --- lib/pleroma/announcement.ex | 30 ++++++++++++++++++++-- .../web/admin_api/views/announcement_view.ex | 2 +- lib/pleroma/web/api_spec/schemas/announcement.ex | 8 +++++- 3 files changed, 36 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index 6c11eff7e..ad372629d 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -18,13 +18,14 @@ defmodule Pleroma.Announcement do field(:data, :map) field(:starts_at, :naive_datetime) field(:ends_at, :naive_datetime) + field(:rendered, :map) timestamps() end def change(struct, params \\ %{}) do struct - |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at]) + |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered]) |> validate_required([:data]) end @@ -42,6 +43,21 @@ defmodule Pleroma.Announcement do params |> Map.merge(%{data: merged_data}) + |> add_rendered_properties() + end + + def add_rendered_properties(params) do + {content_html, _, _} = + Pleroma.Web.CommonAPI.Utils.format_input(params.data["content"], "text/plain", + mentions_format: :full + ) + + rendered = %{ + "content" => content_html + } + + params + |> Map.put(:rendered, rendered) end def add(params) do @@ -100,9 +116,18 @@ defmodule Pleroma.Announcement do %{} end + admin_extra_params = + case Keyword.fetch(opts, :admin) do + {:ok, true} -> + %{pleroma: %{raw_content: announcement.data["content"]}} + + _ -> + %{} + end + base = %{ id: announcement.id, - content: announcement.data["content"], + content: announcement.rendered["content"], starts_at: announcement.starts_at, ends_at: announcement.ends_at, all_day: announcement.data["all_day"], @@ -117,6 +142,7 @@ defmodule Pleroma.Announcement do base |> Map.merge(extra_params) + |> Map.merge(admin_extra_params) end # "visible" means: diff --git a/lib/pleroma/web/admin_api/views/announcement_view.ex b/lib/pleroma/web/admin_api/views/announcement_view.ex index 8fbdc338a..a35bd60cf 100644 --- a/lib/pleroma/web/admin_api/views/announcement_view.ex +++ b/lib/pleroma/web/admin_api/views/announcement_view.ex @@ -10,6 +10,6 @@ defmodule Pleroma.Web.AdminAPI.AnnouncementView do end def render("show.json", %{announcement: announcement}) do - Pleroma.Announcement.render_json(announcement) + Pleroma.Announcement.render_json(announcement, admin: true) end end diff --git a/lib/pleroma/web/api_spec/schemas/announcement.ex b/lib/pleroma/web/api_spec/schemas/announcement.ex index 094fd7c68..67d129ef6 100644 --- a/lib/pleroma/web/api_spec/schemas/announcement.ex +++ b/lib/pleroma/web/api_spec/schemas/announcement.ex @@ -33,7 +33,13 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Announcement do statuses: %Schema{type: :array}, tags: %Schema{type: :array}, emojis: %Schema{type: :array}, - reactions: %Schema{type: :array} + reactions: %Schema{type: :array}, + pleroma: %Schema{ + type: :object, + properties: %{ + raw_content: %Schema{type: :string} + } + } } }) end -- cgit v1.2.3 From 0c78ab4a88d59358a0a5e24a76cbb4cdb2c2d402 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 18 Mar 2022 09:36:13 -0400 Subject: Use utc_datetime in db schema --- lib/pleroma/announcement.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex index ad372629d..d97c5e728 100644 --- a/lib/pleroma/announcement.ex +++ b/lib/pleroma/announcement.ex @@ -16,11 +16,11 @@ defmodule Pleroma.Announcement do schema "announcements" do field(:data, :map) - field(:starts_at, :naive_datetime) - field(:ends_at, :naive_datetime) + field(:starts_at, :utc_datetime) + field(:ends_at, :utc_datetime) field(:rendered, :map) - timestamps() + timestamps(type: :utc_datetime) end def change(struct, params \\ %{}) do @@ -155,6 +155,6 @@ defmodule Pleroma.Announcement do end def list_all_visible do - list_all_visible_when(NaiveDateTime.utc_now()) + list_all_visible_when(DateTime.now("Etc/UTC") |> elem(1)) end end -- cgit v1.2.3 From 7d1dae3befbecbeeb72768afe4f5a23a59ba4f05 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 2 Apr 2022 02:25:13 -0400 Subject: Restrict mastodon api announcements to logged-in users only --- .../web/api_spec/operations/announcement_operation.ex | 1 + .../web/mastodon_api/controllers/announcement_controller.ex | 12 +++++------- lib/pleroma/web/router.ex | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex index a66073b8b..71be0002a 100644 --- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex +++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex @@ -18,6 +18,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do tags: ["Announcement"], summary: "Retrieve a list of announcements", operationId: "MastodonAPI.AnnouncementController.index", + security: [%{"oAuth" => []}], responses: %{ 200 => Operation.response("Response", "application/json", list_of_announcements()), 403 => Operation.response("Forbidden", "application/json", ApiError) diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex index e6da7892c..080af96d5 100644 --- a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex @@ -15,20 +15,18 @@ defmodule Pleroma.Web.MastodonAPI.AnnouncementController do plug(Pleroma.Web.ApiSpec.CastAndValidate) - # MastodonAPI specs do not have oauth requirements for showing - # announcements, but we have "private instance" options. When that - # is set, require read:accounts scope, symmetric to write:accounts - # for `mark_read`. + # Mastodon docs say this only requires a user token, no scopes needed + # As the op `|` requires at least one scope to be present, we use `&` here. plug( OAuthScopesPlug, - %{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]} - when action in [:show, :index] + %{scopes: [], op: :&} + when action in [:index] ) # Same as in MastodonAPI specs plug( OAuthScopesPlug, - %{fallback: :proceed_unauthenticated, scopes: ["write:accounts"]} + %{scopes: ["write:accounts"]} when action in [:mark_read] ) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index af56494a2..7bbc20275 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -582,6 +582,7 @@ defmodule Pleroma.Web.Router do get("/timelines/direct", TimelineController, :direct) get("/timelines/list/:list_id", TimelineController, :list) + get("/announcements", AnnouncementController, :index) post("/announcements/:id/dismiss", AnnouncementController, :mark_read) end @@ -627,8 +628,6 @@ defmodule Pleroma.Web.Router do get("/polls/:id", PollController, :show) get("/directory", DirectoryController, :index) - - get("/announcements", AnnouncementController, :index) end scope "/api/v2", Pleroma.Web.MastodonAPI do -- cgit v1.2.3