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 4ea9886faaddee3ca681e1eacd4862e77928772a Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 9 Jan 2022 20:00:12 +0100 Subject: EctoType: Add MIME validator --- lib/pleroma/constants.ex | 6 ++++++ .../activity_pub/object_validators/mime.ex | 25 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex (limited to 'lib') diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index a42c71d23..7b63ab06e 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -27,4 +27,10 @@ defmodule Pleroma.Constants do do: ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css) ) + + # basic regex, just there to weed out potential mistakes + # https://datatracker.ietf.org/doc/html/rfc2045#section-5.1 + const(mime_regex, + do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/ + ) end diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex new file mode 100644 index 000000000..31d51577d --- /dev/null +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex @@ -0,0 +1,25 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MIME do + use Ecto.Type + + require Pleroma.Constants + + def type, do: :string + + def cast(mime) when is_binary(mime) do + if mime =~ Pleroma.Constants.mime_regex() do + {:ok, mime} + else + {:ok, "application/octet-stream"} + end + end + + def cast(_), do: :error + + def dump(data), do: {:ok, data} + + def load(data), do: {:ok, data} +end -- cgit v1.2.3 From 030183b35f22001cf543bc94061614eb0348a0cf Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 9 Jan 2022 20:01:16 +0100 Subject: AttachmentValidator: Use custom ecto type and regex for "mediaType" --- .../activity_pub/object_validators/attachment_validator.ex | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index d1c61ac82..8b641d88d 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -12,14 +12,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do @primary_key false embedded_schema do field(:type, :string) - field(:mediaType, :string, default: "application/octet-stream") + field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream") field(:name, :string) field(:blurhash, :string) embeds_many :url, UrlObjectValidator, primary_key: false do field(:type, :string) field(:href, ObjectValidators.Uri) - field(:mediaType, :string, default: "application/octet-stream") + field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream") field(:width, :integer) field(:height, :integer) end @@ -59,13 +59,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do end def fix_media_type(data) do - data = Map.put_new(data, "mediaType", data["mimeType"]) - - if is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] do - data - else - Map.put(data, "mediaType", "application/octet-stream") - end + Map.put_new(data, "mediaType", data["mimeType"]) end defp handle_href(href, mediaType, data) do -- cgit v1.2.3 From 83338c25a570e842944a5765cfbec55822ff4ae7 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 9 Jan 2022 20:02:03 +0100 Subject: Transmogrifier: Use validating regex for "mediaType" --- lib/pleroma/web/activity_pub/transmogrifier.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index a70330f0e..d6622df86 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -203,13 +203,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do media_type = cond do - is_map(url) && MIME.extensions(url["mediaType"]) != [] -> + is_map(url) && url =~ Pleroma.Constants.mime_regex() -> url["mediaType"] - is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] -> + is_bitstring(data["mediaType"]) && data["mediaType"] =~ Pleroma.Constants.mime_regex() -> data["mediaType"] - is_bitstring(data["mimeType"]) && MIME.extensions(data["mimeType"]) != [] -> + is_bitstring(data["mimeType"]) && data["mimeType"] =~ Pleroma.Constants.mime_regex() -> data["mimeType"] true -> -- 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 From a1587743641c5719f5b297971c0ed69e867f8241 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bonicoli Date: Fri, 6 May 2022 00:30:36 +0200 Subject: hackney adapter helper & reverse proxy client: enable TLSv1.3 The list of TLS versions was added by 8bd2b6eb138ace3408a03c78ecc339fc35b19f10 when hackney version was pinned to 1.15.2. Later hackney version was upgraded (166455c88441b22455d996ed528ed4804514a3c0) but the list of TLS versions wasn't removed. From the hackney point of view, this list has been replaced by the OTP defaults since 0.16.0 (734694ea4e24f267864c459a2f050e943adc6694). It looks like the same issue already occurred before: 0cb7b0ea8477bdd7af2e5e9071843be5b8623dff. A way to test this issue (where example.com is an ActivityPub site which uses TLSv1.3 only): $ PLEROMA_CONFIG_PATH=/path/to/config.exs pleroma start_iex Erlang/OTP 22 [erts-10.7.2.16] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [hipe] Erlang/OTP 22 [erts-10.7.2.16] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [hipe] Interactive Elixir (1.10.4) - press Ctrl+C to exit (type h() ENTER for help) iex(pleroma@127.0.0.1)2> Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id("https://example.com/@/Nick/") {:error, {:tls_alert, {:protocol_version, 'TLS client: In state hello received SERVER ALERT: Fatal - Protocol Version\n'}}} With this patch, the output is the expected one: iex(pleroma@127.0.0.1)3> Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id("https://example.com/@/Nick/") {:error, {:ok, %{ "@context" => [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", %{ "Emoji" => "toot:Emoji", "Hashtag" => "as:Hashtag", "atomUri" => "ostatus:atomUri", "conversation" => "ostatus:conversation", "featured" => "toot:featured", "focalPoint" => %{"@container" => "@list", "@id" => "toot:focalPoint"}, "inReplyToAtomUri" => "ostatus:inReplyToAtomUri", "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", "movedTo" => "as:movedTo", "ostatus" => "http://ostatus.org#", "sensitive" => "as:sensitive", "toot" => "http://joinmastodon.org/ns#" } ], "endpoints" => %{"sharedInbox" => "https://example.com/inbox"}, "followers" => "https://example.com/@/Nick/followers", "following" => nil, "icon" => %{ "type" => "Image", "url" => "https://example.com/static/media/[...].png" }, "id" => "https://example.com/@/Nick/", "inbox" => "https://example.com/@/Nick/inbox", "liked" => nil, "name" => "Nick", "outbox" => "https://example.com/@/Nick/outbox", "preferredUsername" => "Nick", "publicKey" => %{ "id" => "https://example.com/@/Nick/#main-key", "owner" => "https://example.com/@/Nick/", "publicKeyPem" => "[...] }, "summary" => "", "type" => "Person", "url" => "https://example.com/@/Nick/" }} A way to test the reverse proxy bits of this issue (where example.com allows TLSv1.3 only): iex(pleroma@127.0.0.1)1> Pleroma.ReverseProxy.Client.Hackney.request("GET", "https://example.com", [], []) {:error, {:tls_alert, {:protocol_version, 'TLS client: In state hello received SERVER ALERT: Fatal - Protocol Version\n'}}} --- lib/pleroma/http/adapter_helper/hackney.ex | 4 ---- lib/pleroma/reverse_proxy/client/hackney.ex | 1 - 2 files changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/http/adapter_helper/hackney.ex b/lib/pleroma/http/adapter_helper/hackney.ex index b4f2f0cc2..f3be1f3d0 100644 --- a/lib/pleroma/http/adapter_helper/hackney.ex +++ b/lib/pleroma/http/adapter_helper/hackney.ex @@ -24,10 +24,6 @@ defmodule Pleroma.HTTP.AdapterHelper.Hackney do |> Pleroma.HTTP.AdapterHelper.maybe_add_proxy(proxy) end - defp add_scheme_opts(opts, %URI{scheme: "https"}) do - Keyword.put(opts, :ssl_options, versions: [:"tlsv1.2", :"tlsv1.1", :tlsv1]) - end - defp add_scheme_opts(opts, _), do: opts defp maybe_add_with_body(opts) do diff --git a/lib/pleroma/reverse_proxy/client/hackney.ex b/lib/pleroma/reverse_proxy/client/hackney.ex index 41eaf06cc..d3e986912 100644 --- a/lib/pleroma/reverse_proxy/client/hackney.ex +++ b/lib/pleroma/reverse_proxy/client/hackney.ex @@ -7,7 +7,6 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do @impl true def request(method, url, headers, body, opts \\ []) do - opts = Keyword.put(opts, :ssl_options, versions: [:"tlsv1.2", :"tlsv1.1", :tlsv1]) :hackney.request(method, url, headers, body, opts) end -- cgit v1.2.3 From cd316d7269a6cac1e9edb732b202343001b82399 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 14 Feb 2022 13:14:25 +0100 Subject: Use EXIF data of image to prefill image description During attachment upload Pleroma returns a "description" field. Pleroma-fe has an MR to use that to pre-fill the image description field, * This MR allows Pleroma to read the EXIF data during upload and return the description to the FE * If a description is already present (e.g. because a previous module added it), it will use that * Otherwise it will read from the EXIF data. First it will check -ImageDescription, if that's empty, it will check -iptc:Caption-Abstract * If no description is found, it will simply return nil, just like before * When people set up a new instance, they will be asked if they want to read metadata and this module will be activated if so This was taken from an MR i did on Pleroma and isn't finished yet. --- lib/mix/tasks/pleroma/instance.ex | 26 ++++++++++++++ lib/pleroma/application_requirements.ex | 1 + lib/pleroma/upload.ex | 27 ++++++++++---- lib/pleroma/upload/filter/exiftool_read_data.ex | 47 +++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 lib/pleroma/upload/filter/exiftool_read_data.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index f292fc762..d206e1622 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -35,6 +35,7 @@ defmodule Mix.Tasks.Pleroma.Instance do listen_ip: :string, listen_port: :string, strip_uploads: :string, + read_uploads_data: :string, anonymize_uploads: :string, dedupe_uploads: :string ], @@ -178,6 +179,23 @@ defmodule Mix.Tasks.Pleroma.Instance do strip_uploads_default ) === "y" + {read_uploads_data_message, read_uploads_data_default} = + if Pleroma.Utils.command_available?("exiftool") do + {"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as installed. (y/n)", + "y"} + else + {"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as not installed, please install it if you answer yes. (y/n)", + "n"} + end + + read_uploads_data = + get_option( + options, + :read_uploads_data, + read_uploads_data_message, + read_uploads_data_default + ) === "y" + anonymize_uploads = get_option( options, @@ -230,6 +248,7 @@ defmodule Mix.Tasks.Pleroma.Instance do upload_filters: upload_filters(%{ strip: strip_uploads, + read_data: read_uploads_data, anonymize: anonymize_uploads, dedupe: dedupe_uploads }) @@ -303,6 +322,13 @@ defmodule Mix.Tasks.Pleroma.Instance do [] end + enabled_filters = + if filters.read_data do + enabled_filters ++ [Pleroma.Upload.Filter.ExiftoolReadData] + else + enabled_filters + end + enabled_filters = if filters.anonymize do enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename] diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex index 06d388694..ea1ee71c0 100644 --- a/lib/pleroma/application_requirements.ex +++ b/lib/pleroma/application_requirements.ex @@ -165,6 +165,7 @@ defmodule Pleroma.ApplicationRequirements do defp check_system_commands!(:ok) do filter_commands_statuses = [ check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"), + check_filter(Pleroma.Upload.Filter.ExiftoolReadData, "exiftool"), check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"), check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"), check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"), diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 242813dcd..db2909276 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -60,12 +60,23 @@ defmodule Pleroma.Upload do width: integer(), height: integer(), blurhash: String.t(), + description: String.t(), path: String.t() } - defstruct [:id, :name, :tempfile, :content_type, :width, :height, :blurhash, :path] - - defp get_description(opts, upload) do - case {opts[:description], Pleroma.Config.get([Pleroma.Upload, :default_description])} do + defstruct [ + :id, + :name, + :tempfile, + :content_type, + :width, + :height, + :blurhash, + :description, + :path + ] + + defp get_description(upload) do + case {upload.description, Pleroma.Config.get([Pleroma.Upload, :default_description])} do {description, _} when is_binary(description) -> description {_, :filename} -> upload.name {_, str} when is_binary(str) -> str @@ -81,7 +92,7 @@ defmodule Pleroma.Upload do with {:ok, upload} <- prepare_upload(upload, opts), upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"}, {:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload), - description = get_description(opts, upload), + description = get_description(upload), {_, true} <- {:description_limit, String.length(description) <= Pleroma.Config.get([:instance, :description_limit])}, @@ -152,7 +163,8 @@ defmodule Pleroma.Upload do id: UUID.generate(), name: file.filename, tempfile: file.path, - content_type: file.content_type + content_type: file.content_type, + description: opts.description }} end end @@ -172,7 +184,8 @@ defmodule Pleroma.Upload do id: UUID.generate(), name: hash <> "." <> ext, tempfile: tmp_path, - content_type: content_type + content_type: content_type, + description: opts.description }} end end diff --git a/lib/pleroma/upload/filter/exiftool_read_data.ex b/lib/pleroma/upload/filter/exiftool_read_data.ex new file mode 100644 index 000000000..c8bedfbf8 --- /dev/null +++ b/lib/pleroma/upload/filter/exiftool_read_data.ex @@ -0,0 +1,47 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.ExiftoolReadData do + @moduledoc """ + Gets the description from the related EXIF tags and provides them in the response if no description is provided yet. + It will first check ImageDescription, when that's too long or empty, it will check iptc:Caption-Abstract. + When the description is too long (see `:instance, :description_limit`), an empty string is returned. + """ + @behaviour Pleroma.Upload.Filter + + @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} + + def filter(%Pleroma.Upload{description: description}) + when is_binary(description), + do: {:ok, :noop} + + def filter(%Pleroma.Upload{tempfile: file} = upload), + do: {:ok, :filtered, upload |> Map.put(:description, read_description_from_exif_data(file))} + + def filter(_, _), do: {:ok, :noop} + + defp read_description_from_exif_data(file) do + nil + |> read_when_empty(file, "-ImageDescription") + |> read_when_empty(file, "-iptc:Caption-Abstract") + end + + defp read_when_empty(current_description, _, _) when is_binary(current_description), + do: current_description + + defp read_when_empty(_, file, tag) do + try do + {tag_content, 0} = + System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true) + + if tag_content != "" and + String.length(tag_content) <= + Pleroma.Config.get([:instance, :description_limit]), + do: tag_content, + else: nil + rescue + _ in ErlangError -> nil + end + end +end -- cgit v1.2.3 From 551721e41a0bd98bb840baca48415a781cc463a7 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 20 Feb 2022 12:59:42 +0100 Subject: Rename the new module --- lib/mix/tasks/pleroma/instance.ex | 18 ++++----- lib/pleroma/application_requirements.ex | 2 +- lib/pleroma/upload/filter/exiftool.ex | 31 -------------- lib/pleroma/upload/filter/exiftool/exiftool.ex | 31 ++++++++++++++ .../upload/filter/exiftool/read_description.ex | 47 ++++++++++++++++++++++ lib/pleroma/upload/filter/exiftool_read_data.ex | 47 ---------------------- 6 files changed, 88 insertions(+), 88 deletions(-) delete mode 100644 lib/pleroma/upload/filter/exiftool.ex create mode 100644 lib/pleroma/upload/filter/exiftool/exiftool.ex create mode 100644 lib/pleroma/upload/filter/exiftool/read_description.ex delete mode 100644 lib/pleroma/upload/filter/exiftool_read_data.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index d206e1622..40a8a2320 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -35,7 +35,7 @@ defmodule Mix.Tasks.Pleroma.Instance do listen_ip: :string, listen_port: :string, strip_uploads: :string, - read_uploads_data: :string, + read_uploads_description: :string, anonymize_uploads: :string, dedupe_uploads: :string ], @@ -179,7 +179,7 @@ defmodule Mix.Tasks.Pleroma.Instance do strip_uploads_default ) === "y" - {read_uploads_data_message, read_uploads_data_default} = + {read_uploads_description_message, read_uploads_description_default} = if Pleroma.Utils.command_available?("exiftool") do {"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as installed. (y/n)", "y"} @@ -188,12 +188,12 @@ defmodule Mix.Tasks.Pleroma.Instance do "n"} end - read_uploads_data = + read_uploads_description = get_option( options, - :read_uploads_data, - read_uploads_data_message, - read_uploads_data_default + :read_uploads_description, + read_uploads_description_message, + read_uploads_description_default ) === "y" anonymize_uploads = @@ -248,7 +248,7 @@ defmodule Mix.Tasks.Pleroma.Instance do upload_filters: upload_filters(%{ strip: strip_uploads, - read_data: read_uploads_data, + read_description: read_uploads_description, anonymize: anonymize_uploads, dedupe: dedupe_uploads }) @@ -323,8 +323,8 @@ defmodule Mix.Tasks.Pleroma.Instance do end enabled_filters = - if filters.read_data do - enabled_filters ++ [Pleroma.Upload.Filter.ExiftoolReadData] + if filters.read_description do + enabled_filters ++ [Pleroma.Upload.Filter.Exiftool.ReadDescription] else enabled_filters end diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex index ea1ee71c0..117aa88cb 100644 --- a/lib/pleroma/application_requirements.ex +++ b/lib/pleroma/application_requirements.ex @@ -165,7 +165,7 @@ defmodule Pleroma.ApplicationRequirements do defp check_system_commands!(:ok) do filter_commands_statuses = [ check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"), - check_filter(Pleroma.Upload.Filter.ExiftoolReadData, "exiftool"), + check_filter(Pleroma.Upload.Filter.Exiftool.ReadDescription, "exiftool"), check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"), check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"), check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"), diff --git a/lib/pleroma/upload/filter/exiftool.ex b/lib/pleroma/upload/filter/exiftool.ex deleted file mode 100644 index 36cc045c2..000000000 --- a/lib/pleroma/upload/filter/exiftool.ex +++ /dev/null @@ -1,31 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Upload.Filter.Exiftool do - @moduledoc """ - Strips GPS related EXIF tags and overwrites the file in place. - Also strips or replaces filesystem metadata e.g., timestamps. - """ - @behaviour Pleroma.Upload.Filter - - @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} - - # Formats not compatible with exiftool at this time - def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} - def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} - - def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do - try do - case System.cmd("exiftool", ["-overwrite_original", "-gps:all=", file], parallelism: true) do - {_response, 0} -> {:ok, :filtered} - {error, 1} -> {:error, error} - end - rescue - e in ErlangError -> - {:error, "#{__MODULE__}: #{inspect(e)}"} - end - end - - def filter(_), do: {:ok, :noop} -end diff --git a/lib/pleroma/upload/filter/exiftool/exiftool.ex b/lib/pleroma/upload/filter/exiftool/exiftool.ex new file mode 100644 index 000000000..36cc045c2 --- /dev/null +++ b/lib/pleroma/upload/filter/exiftool/exiftool.ex @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.Exiftool do + @moduledoc """ + Strips GPS related EXIF tags and overwrites the file in place. + Also strips or replaces filesystem metadata e.g., timestamps. + """ + @behaviour Pleroma.Upload.Filter + + @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} + + # Formats not compatible with exiftool at this time + def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} + def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} + + def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do + try do + case System.cmd("exiftool", ["-overwrite_original", "-gps:all=", file], parallelism: true) do + {_response, 0} -> {:ok, :filtered} + {error, 1} -> {:error, error} + end + rescue + e in ErlangError -> + {:error, "#{__MODULE__}: #{inspect(e)}"} + end + end + + def filter(_), do: {:ok, :noop} +end diff --git a/lib/pleroma/upload/filter/exiftool/read_description.ex b/lib/pleroma/upload/filter/exiftool/read_description.ex new file mode 100644 index 000000000..3f7b7c798 --- /dev/null +++ b/lib/pleroma/upload/filter/exiftool/read_description.ex @@ -0,0 +1,47 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do + @moduledoc """ + Gets the description from the related EXIF tags and provides them in the response if no description is provided yet. + It will first check ImageDescription, when that's too long or empty, it will check iptc:Caption-Abstract. + When the description is too long (see `:instance, :description_limit`), an empty string is returned. + """ + @behaviour Pleroma.Upload.Filter + + @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} + + def filter(%Pleroma.Upload{description: description}) + when is_binary(description), + do: {:ok, :noop} + + def filter(%Pleroma.Upload{tempfile: file} = upload), + do: {:ok, :filtered, upload |> Map.put(:description, read_description_from_exif_data(file))} + + def filter(_, _), do: {:ok, :noop} + + defp read_description_from_exif_data(file) do + nil + |> read_when_empty(file, "-ImageDescription") + |> read_when_empty(file, "-iptc:Caption-Abstract") + end + + defp read_when_empty(current_description, _, _) when is_binary(current_description), + do: current_description + + defp read_when_empty(_, file, tag) do + try do + {tag_content, 0} = + System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true) + + if tag_content != "" and + String.length(tag_content) <= + Pleroma.Config.get([:instance, :description_limit]), + do: tag_content, + else: nil + rescue + _ in ErlangError -> nil + end + end +end diff --git a/lib/pleroma/upload/filter/exiftool_read_data.ex b/lib/pleroma/upload/filter/exiftool_read_data.ex deleted file mode 100644 index c8bedfbf8..000000000 --- a/lib/pleroma/upload/filter/exiftool_read_data.ex +++ /dev/null @@ -1,47 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2021 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Upload.Filter.ExiftoolReadData do - @moduledoc """ - Gets the description from the related EXIF tags and provides them in the response if no description is provided yet. - It will first check ImageDescription, when that's too long or empty, it will check iptc:Caption-Abstract. - When the description is too long (see `:instance, :description_limit`), an empty string is returned. - """ - @behaviour Pleroma.Upload.Filter - - @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} - - def filter(%Pleroma.Upload{description: description}) - when is_binary(description), - do: {:ok, :noop} - - def filter(%Pleroma.Upload{tempfile: file} = upload), - do: {:ok, :filtered, upload |> Map.put(:description, read_description_from_exif_data(file))} - - def filter(_, _), do: {:ok, :noop} - - defp read_description_from_exif_data(file) do - nil - |> read_when_empty(file, "-ImageDescription") - |> read_when_empty(file, "-iptc:Caption-Abstract") - end - - defp read_when_empty(current_description, _, _) when is_binary(current_description), - do: current_description - - defp read_when_empty(_, file, tag) do - try do - {tag_content, 0} = - System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true) - - if tag_content != "" and - String.length(tag_content) <= - Pleroma.Config.get([:instance, :description_limit]), - do: tag_content, - else: nil - rescue - _ in ErlangError -> nil - end - end -end -- cgit v1.2.3 From 8303af84ce818b57347db4cd12611c4dd45bdf95 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 20 Feb 2022 13:46:29 +0100 Subject: Rename the Exiftool module No migrations or checks yet --- lib/mix/tasks/pleroma/instance.ex | 18 ++++++------- lib/pleroma/application_requirements.ex | 2 +- lib/pleroma/upload/filter/exiftool/exiftool.ex | 31 ---------------------- .../upload/filter/exiftool/strip_location.ex | 31 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 41 deletions(-) delete mode 100644 lib/pleroma/upload/filter/exiftool/exiftool.ex create mode 100644 lib/pleroma/upload/filter/exiftool/strip_location.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 40a8a2320..5c93f19ff 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -34,7 +34,7 @@ defmodule Mix.Tasks.Pleroma.Instance do static_dir: :string, listen_ip: :string, listen_port: :string, - strip_uploads: :string, + strip_uploads_location: :string, read_uploads_description: :string, anonymize_uploads: :string, dedupe_uploads: :string @@ -162,7 +162,7 @@ defmodule Mix.Tasks.Pleroma.Instance do ) |> Path.expand() - {strip_uploads_message, strip_uploads_default} = + {strip_uploads_location_message, strip_uploads_location_default} = if Pleroma.Utils.command_available?("exiftool") do {"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)", "y"} @@ -171,12 +171,12 @@ defmodule Mix.Tasks.Pleroma.Instance do "n"} end - strip_uploads = + strip_uploads_location = get_option( options, - :strip_uploads, - strip_uploads_message, - strip_uploads_default + :strip_uploads_location, + strip_uploads_location_message, + strip_uploads_location_default ) === "y" {read_uploads_description_message, read_uploads_description_default} = @@ -247,7 +247,7 @@ defmodule Mix.Tasks.Pleroma.Instance do listen_port: listen_port, upload_filters: upload_filters(%{ - strip: strip_uploads, + strip_location: strip_uploads_location, read_description: read_uploads_description, anonymize: anonymize_uploads, dedupe: dedupe_uploads @@ -316,8 +316,8 @@ defmodule Mix.Tasks.Pleroma.Instance do defp upload_filters(filters) when is_map(filters) do enabled_filters = - if filters.strip do - [Pleroma.Upload.Filter.Exiftool] + if filters.strip_location do + [Pleroma.Upload.Filter.Exiftool.StripLocation] else [] end diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex index 117aa88cb..44b1c1705 100644 --- a/lib/pleroma/application_requirements.ex +++ b/lib/pleroma/application_requirements.ex @@ -164,7 +164,7 @@ defmodule Pleroma.ApplicationRequirements do defp check_system_commands!(:ok) do filter_commands_statuses = [ - check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"), + check_filter(Pleroma.Upload.Filter.Exiftool.StripLocation, "exiftool"), check_filter(Pleroma.Upload.Filter.Exiftool.ReadDescription, "exiftool"), check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"), check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"), diff --git a/lib/pleroma/upload/filter/exiftool/exiftool.ex b/lib/pleroma/upload/filter/exiftool/exiftool.ex deleted file mode 100644 index 36cc045c2..000000000 --- a/lib/pleroma/upload/filter/exiftool/exiftool.ex +++ /dev/null @@ -1,31 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Upload.Filter.Exiftool do - @moduledoc """ - Strips GPS related EXIF tags and overwrites the file in place. - Also strips or replaces filesystem metadata e.g., timestamps. - """ - @behaviour Pleroma.Upload.Filter - - @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} - - # Formats not compatible with exiftool at this time - def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} - def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} - - def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do - try do - case System.cmd("exiftool", ["-overwrite_original", "-gps:all=", file], parallelism: true) do - {_response, 0} -> {:ok, :filtered} - {error, 1} -> {:error, error} - end - rescue - e in ErlangError -> - {:error, "#{__MODULE__}: #{inspect(e)}"} - end - end - - def filter(_), do: {:ok, :noop} -end diff --git a/lib/pleroma/upload/filter/exiftool/strip_location.ex b/lib/pleroma/upload/filter/exiftool/strip_location.ex new file mode 100644 index 000000000..6100527d3 --- /dev/null +++ b/lib/pleroma/upload/filter/exiftool/strip_location.ex @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do + @moduledoc """ + Strips GPS related EXIF tags and overwrites the file in place. + Also strips or replaces filesystem metadata e.g., timestamps. + """ + @behaviour Pleroma.Upload.Filter + + @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} + + # Formats not compatible with exiftool at this time + def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} + def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} + + def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do + try do + case System.cmd("exiftool", ["-overwrite_original", "-gps:all=", file], parallelism: true) do + {_response, 0} -> {:ok, :filtered} + {error, 1} -> {:error, error} + end + rescue + e in ErlangError -> + {:error, "#{__MODULE__}: #{inspect(e)}"} + end + end + + def filter(_), do: {:ok, :noop} +end -- cgit v1.2.3 From d0d48a9e8832ed81e67126a2af019981cb761a2b Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 20 Feb 2022 14:46:37 +0100 Subject: Add deprecation warnings --- lib/pleroma/config/deprecation_warnings.ex | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 118dd3acc..4348505e2 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -20,6 +20,43 @@ defmodule Pleroma.Config.DeprecationWarnings do "\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"} ] + def check_exiftool_filter do + filters = Config.get([Pleroma.Upload])[:filters] + + if Pleroma.Upload.Filter.Exiftool in filters do + Logger.warn(""" + !!!DEPRECATION WARNING!!! + Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later: + + ``` + config :pleroma, Pleroma.Upload, + filters: [Pleroma.Upload.Filter.Exiftool] + ``` + + Is now + + + ``` + config :pleroma, Pleroma.Upload, + filters: [Pleroma.Upload.Filter.Exiftool.StripLocation] + ``` + """) + + new_config = + filters + |> Enum.map(fn + Pleroma.Upload.Filter.Exiftool -> Pleroma.Upload.Filter.Exiftool.StripLocation + filter -> filter + end) + + Config.put([Pleroma.Upload, :filters], new_config) + + :error + else + :ok + end + end + def check_simple_policy_tuples do has_strings = Config.get([:mrf_simple]) @@ -180,7 +217,8 @@ defmodule Pleroma.Config.DeprecationWarnings do check_old_chat_shoutbox(), check_quarantined_instances_tuples(), check_transparency_exclusions_tuples(), - check_simple_policy_tuples() + check_simple_policy_tuples(), + check_exiftool_filter() ] |> Enum.reduce(:ok, fn :ok, :ok -> :ok -- cgit v1.2.3 From 81afaee37436f1802f4e0a6d33d9bb8121e51f48 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 22 Feb 2022 18:18:10 +0100 Subject: Better way of getting keys I used keyword_list[:key], but if the key doesn't exist, it will return nil. I actually expect a list and further down the code I use that list. I believe the key should always be present, but in case it's not, it's better to return an empty list instead of nil. That way the code wont fail further down the line. --- lib/pleroma/config/deprecation_warnings.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 4348505e2..599f1d3cf 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Config.DeprecationWarnings do ] def check_exiftool_filter do - filters = Config.get([Pleroma.Upload])[:filters] + filters = Config.get([Pleroma.Upload]) |> Keyword.get(:filters, []) if Pleroma.Upload.Filter.Exiftool in filters do Logger.warn(""" -- cgit v1.2.3 From 8c761942b1963bff08d98eeb22b84b0f327d68e4 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 21 May 2022 11:31:14 +0200 Subject: update moduledoc --- lib/pleroma/upload/filter/exiftool/read_description.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/upload/filter/exiftool/read_description.ex b/lib/pleroma/upload/filter/exiftool/read_description.ex index 3f7b7c798..a69f79124 100644 --- a/lib/pleroma/upload/filter/exiftool/read_description.ex +++ b/lib/pleroma/upload/filter/exiftool/read_description.ex @@ -4,9 +4,9 @@ defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do @moduledoc """ - Gets the description from the related EXIF tags and provides them in the response if no description is provided yet. - It will first check ImageDescription, when that's too long or empty, it will check iptc:Caption-Abstract. - When the description is too long (see `:instance, :description_limit`), an empty string is returned. + Gets a valid description from the related EXIF tags and provides them in the response if no description is provided yet. + It will first check ImageDescription, when that doesn't probide a valid description, it will check iptc:Caption-Abstract. + A valid description means the fields are filled in and not too long (see `:instance, :description_limit`). """ @behaviour Pleroma.Upload.Filter -- cgit v1.2.3 From 56227ef7ba097c6be39a7e70b67c426a3016e0ab Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 1 Jul 2022 12:31:34 +0200 Subject: Descriptions from exif data with only whitespeces are considered empty I noticed that pictures taken with Ubuntu-Touch have whitespace in one of the fields This should just be ignored imo --- lib/pleroma/upload/filter/exiftool/read_description.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/upload/filter/exiftool/read_description.ex b/lib/pleroma/upload/filter/exiftool/read_description.ex index a69f79124..03d698a81 100644 --- a/lib/pleroma/upload/filter/exiftool/read_description.ex +++ b/lib/pleroma/upload/filter/exiftool/read_description.ex @@ -35,6 +35,8 @@ defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do {tag_content, 0} = System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true) + tag_content = String.trim(tag_content) + if tag_content != "" and String.length(tag_content) <= Pleroma.Config.get([:instance, :description_limit]), -- cgit v1.2.3