diff --git a/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
new file mode 100644
index 000000000..85a22aa0b
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
@@ -0,0 +1,102 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Reference
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.Account
+ alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["Scrobbles"],
+ summary: "Creates a new Listen activity for an account",
+ security: [%{"oAuth" => ["write"]}],
+ operationId: "PleromaAPI.ScrobbleController.create",
+ requestBody: request_body("Parameters", create_request(), requried: true),
+ responses: %{
+ 200 => Operation.response("Scrobble", "application/json", scrobble())
+ }
+ }
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["Scrobbles"],
+ summary: "Requests a list of current and recent Listen activities for an account",
+ operationId: "PleromaAPI.ScrobbleController.index",
+ parameters: [
+ %Reference{"$ref": "#/components/parameters/accountIdOrNickname"} | pagination_params()
+ ],
+ security: [%{"oAuth" => ["read"]}],
+ responses: %{
+ 200 =>
+ Operation.response("Array of Scrobble", "application/json", %Schema{
+ type: :array,
+ items: scrobble()
+ })
+ }
+ }
+ end
+
+ defp create_request do
+ %Schema{
+ type: :object,
+ required: [:title],
+ properties: %{
+ title: %Schema{type: :string, description: "The title of the media playing"},
+ album: %Schema{type: :string, description: "The album of the media playing"},
+ artist: %Schema{type: :string, description: "The artist of the media playing"},
+ length: %Schema{type: :integer, description: "The length of the media playing"},
+ visibility: %Schema{
+ allOf: [VisibilityScope],
+ default: "public",
+ description: "Scrobble visibility"
+ }
+ },
+ example: %{
+ "title" => "Some Title",
+ "artist" => "Some Artist",
+ "album" => "Some Album",
+ "length" => 180_000
+ }
+ }
+ end
+
+ defp scrobble do
+ %Schema{
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string},
+ account: Account,
+ title: %Schema{type: :string, description: "The title of the media playing"},
+ album: %Schema{type: :string, description: "The album of the media playing"},
+ artist: %Schema{type: :string, description: "The artist of the media playing"},
+ length: %Schema{
+ type: :integer,
+ description: "The length of the media playing",
+ nullable: true
+ },
+ created_at: %Schema{type: :string, format: :"date-time"}
+ },
+ example: %{
+ "id" => "1234",
+ "account" => Account.schema().example,
+ "title" => "Some Title",
+ "artist" => "Some Artist",
+ "album" => "Some Album",
+ "length" => 180_000,
+ "created_at" => "2019-09-28T12:40:45.000Z"
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 7c94f16b6..447dbe4e6 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -347,11 +347,14 @@ def check_expiry_date(expiry_str) do
|> check_expiry_date()
end
- def listen(user, %{"title" => _} = data) do
- with visibility <- data["visibility"] || "public",
- {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
+ def listen(user, data) do
+ visibility = Map.get(data, :visibility, "public")
+
+ with {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
listen_data <-
- Map.take(data, ["album", "artist", "title", "length"])
+ data
+ |> Map.take([:album, :artist, :title, :length])
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Audio")
|> Map.put("to", to)
|> Map.put("cc", cc)
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 05a26017a..8e3715093 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -436,27 +436,6 @@ def render("attachment.json", %{attachment: attachment}) do
}
end
- def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
- object = Object.normalize(activity)
-
- user = get_user(activity.data["actor"])
- created_at = Utils.to_masto_date(activity.data["published"])
-
- %{
- id: activity.id,
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
- created_at: created_at,
- title: object.data["title"] |> HTML.strip_tags(),
- artist: object.data["artist"] |> HTML.strip_tags(),
- album: object.data["album"] |> HTML.strip_tags(),
- length: object.data["length"]
- }
- end
-
- def render("listens.json", opts) do
- safe_render_many(opts.activities, StatusView, "listen.json", opts)
- end
-
def render("context.json", %{activity: activity, activities: activities, user: user}) do
%{ancestors: ancestors, descendants: descendants} =
activities
diff --git a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
index 22da6c0ad..8665ca56c 100644
--- a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
@@ -5,34 +5,27 @@
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MastodonAPI.StatusView
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(
OAuthScopesPlug,
- %{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :user_scrobbles
+ %{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :index
)
- plug(OAuthScopesPlug, %{scopes: ["write"]} when action != :user_scrobbles)
+ plug(OAuthScopesPlug, %{scopes: ["write"]} when action == :create)
- def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do
- params =
- if !params["length"] do
- params
- else
- params
- |> Map.put("length", fetch_integer_param(params, "length"))
- end
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaScrobbleOperation
+ def create(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, activity} <- CommonAPI.listen(user, params) do
- conn
- |> put_view(StatusView)
- |> render("listen.json", %{activity: activity, for: user})
+ render(conn, "show.json", activity: activity, for: user)
else
{:error, message} ->
conn
@@ -41,16 +34,18 @@ def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do
end
end
- def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
- params = Map.put(params, "type", ["Listen"])
+ def index(%{assigns: %{user: reading_user}} = conn, %{id: id} = params) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(id, for: reading_user) do
+ params =
+ params
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
+ |> Map.put("type", ["Listen"])
activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params)
conn
|> add_link_headers(activities)
- |> put_view(StatusView)
- |> render("listens.json", %{
+ |> render("index.json", %{
activities: activities,
for: reading_user,
as: :activity
diff --git a/lib/pleroma/web/pleroma_api/views/scrobble_view.ex b/lib/pleroma/web/pleroma_api/views/scrobble_view.ex
new file mode 100644
index 000000000..bbff93abe
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/scrobble_view.ex
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ScrobbleView do
+ use Pleroma.Web, :view
+
+ require Pleroma.Constants
+
+ alias Pleroma.Activity
+ alias Pleroma.HTML
+ alias Pleroma.Object
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ def render("show.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
+ object = Object.normalize(activity)
+
+ user = StatusView.get_user(activity.data["actor"])
+ created_at = Utils.to_masto_date(activity.data["published"])
+
+ %{
+ id: activity.id,
+ account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ created_at: created_at,
+ title: object.data["title"] |> HTML.strip_tags(),
+ artist: object.data["artist"] |> HTML.strip_tags(),
+ album: object.data["album"] |> HTML.strip_tags(),
+ length: object.data["length"]
+ }
+ end
+
+ def render("index.json", opts) do
+ safe_render_many(opts.activities, __MODULE__, "show.json", opts)
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index d77a61361..369c54cf4 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -325,7 +325,7 @@ defmodule Pleroma.Web.Router do
get("/mascot", MascotController, :show)
put("/mascot", MascotController, :update)
- post("/scrobble", ScrobbleController, :new_scrobble)
+ post("/scrobble", ScrobbleController, :create)
end
scope [] do
@@ -345,7 +345,7 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
- get("/accounts/:id/scrobbles", ScrobbleController, :user_scrobbles)
+ get("/accounts/:id/scrobbles", ScrobbleController, :index)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index fd8299013..52e95397c 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -841,10 +841,10 @@ test "returns a valid activity" do
{:ok, activity} =
CommonAPI.listen(user, %{
- "title" => "lain radio episode 1",
- "album" => "lain radio",
- "artist" => "lain",
- "length" => 180_000
+ title: "lain radio episode 1",
+ album: "lain radio",
+ artist: "lain",
+ length: 180_000
})
object = Object.normalize(activity)
@@ -859,11 +859,11 @@ test "respects visibility=private" do
{:ok, activity} =
CommonAPI.listen(user, %{
- "title" => "lain radio episode 1",
- "album" => "lain radio",
- "artist" => "lain",
- "length" => 180_000,
- "visibility" => "private"
+ title: "lain radio episode 1",
+ album: "lain radio",
+ artist: "lain",
+ length: 180_000,
+ visibility: "private"
})
object = Object.normalize(activity)
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index 5d7adbe29..43e3bdca1 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -620,14 +620,4 @@ test "visibility/list" do
assert status.visibility == "list"
end
-
- test "successfully renders a Listen activity (pleroma extension)" do
- listen_activity = insert(:listen)
-
- status = StatusView.render("listen.json", activity: listen_activity)
-
- assert status.length == listen_activity.data["object"]["length"]
- assert status.title == listen_activity.data["object"]["title"]
- assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
- end
end
diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs
index 1b945040c..f39c07ac6 100644
--- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs
+++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs
@@ -12,14 +12,16 @@ test "works correctly" do
%{conn: conn} = oauth_access(["write"])
conn =
- post(conn, "/api/v1/pleroma/scrobble", %{
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/pleroma/scrobble", %{
"title" => "lain radio episode 1",
"artist" => "lain",
"album" => "lain radio",
"length" => "180000"
})
- assert %{"title" => "lain radio episode 1"} = json_response(conn, 200)
+ assert %{"title" => "lain radio episode 1"} = json_response_and_validate_schema(conn, 200)
end
end
@@ -29,28 +31,28 @@ test "works correctly" do
{:ok, _activity} =
CommonAPI.listen(user, %{
- "title" => "lain radio episode 1",
- "artist" => "lain",
- "album" => "lain radio"
+ title: "lain radio episode 1",
+ artist: "lain",
+ album: "lain radio"
})
{:ok, _activity} =
CommonAPI.listen(user, %{
- "title" => "lain radio episode 2",
- "artist" => "lain",
- "album" => "lain radio"
+ title: "lain radio episode 2",
+ artist: "lain",
+ album: "lain radio"
})
{:ok, _activity} =
CommonAPI.listen(user, %{
- "title" => "lain radio episode 3",
- "artist" => "lain",
- "album" => "lain radio"
+ title: "lain radio episode 3",
+ artist: "lain",
+ album: "lain radio"
})
conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/scrobbles")
- result = json_response(conn, 200)
+ result = json_response_and_validate_schema(conn, 200)
assert length(result) == 3
end
diff --git a/test/web/pleroma_api/views/scrobble_view_test.exs b/test/web/pleroma_api/views/scrobble_view_test.exs
new file mode 100644
index 000000000..6bdb56509
--- /dev/null
+++ b/test/web/pleroma_api/views/scrobble_view_test.exs
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.StatusViewTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.PleromaAPI.ScrobbleView
+
+ import Pleroma.Factory
+
+ test "successfully renders a Listen activity (pleroma extension)" do
+ listen_activity = insert(:listen)
+
+ status = ScrobbleView.render("show.json", activity: listen_activity)
+
+ assert status.length == listen_activity.data["object"]["length"]
+ assert status.title == listen_activity.data["object"]["title"]
+ end
+end