Merge branch 'develop' into chore/remove-deprecated-functions
This commit is contained in:
commit
e8ad9b6dfe
20 changed files with 13 additions and 532 deletions
|
@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Scrobbling support
|
||||||
|
|
||||||
## 2022.07
|
## 2022.07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
10
README.md
10
README.md
|
@ -4,21 +4,21 @@
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
This is a fork of Pleroma, which is a microblogging server software that can federate (= exchange messages with) other servers that support ActivityPub. What that means is that you can host a server for yourself or your friends and stay in control of your online identity, but still exchange messages with people on larger servers. Pleroma will federate with all servers that implement ActivityPub, like Friendica, GNU Social, Hubzilla, Mastodon, Misskey, Peertube, and Pixelfed.
|
This is a fork of Pleroma, which is a microblogging server software that can federate (= exchange messages with) other servers that support ActivityPub. What that means is that you can host a server for yourself or your friends and stay in control of your online identity, but still exchange messages with people on larger servers. Akkoma will federate with all servers that implement ActivityPub, like Friendica, GNU Social, Hubzilla, Mastodon, Misskey, Peertube, and Pixelfed.
|
||||||
|
|
||||||
Akkoma is written in Elixir and uses PostgresSQL for data storage.
|
Akkoma is written in Elixir and uses PostgresSQL for data storage.
|
||||||
|
|
||||||
For clients it supports the [Mastodon client API](https://docs.joinmastodon.org/api/guidelines/) with Pleroma extensions (see the API section on <https://docs.akkoma.dev/stable/>).
|
For clients it supports the [Mastodon client API](https://docs.joinmastodon.org/api/guidelines/) with Pleroma extensions (see the API section on <https://docs.akkoma.dev/stable/>).
|
||||||
|
|
||||||
- [Client Applications for Pleroma](https://docs.akkoma.dev/stable/clients/)
|
- [Client Applications for Akkoma](https://docs.akkoma.dev/stable/clients/)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### OTP releases (Recommended)
|
### OTP releases (Recommended)
|
||||||
If you are running Linux (glibc or musl) on x86, the recommended way to install Pleroma is by using OTP releases. OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it. The installation instructions are available [here](https://docs.akkoma.dev/stable/installation/otp_en/).
|
If you are running Linux (glibc or musl) on x86, the recommended way to install Akkoma is by using OTP releases. OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it. The installation instructions are available [here](https://docs.akkoma.dev/stable/installation/otp_en/).
|
||||||
|
|
||||||
### From Source
|
### From Source
|
||||||
If your platform is not supported, or you just want to be able to edit the source code easily, you may install Pleroma from source.
|
If your platform is not supported, or you just want to be able to edit the source code easily, you may install Akkoma from source.
|
||||||
|
|
||||||
- [Alpine Linux](https://docs.akkoma.dev/stable/installation/alpine_linux_en/)
|
- [Alpine Linux](https://docs.akkoma.dev/stable/installation/alpine_linux_en/)
|
||||||
- [Arch Linux](https://docs.akkoma.dev/stable/installation/arch_linux_en/)
|
- [Arch Linux](https://docs.akkoma.dev/stable/installation/arch_linux_en/)
|
||||||
|
@ -34,7 +34,7 @@ If your platform is not supported, or you just want to be able to edit the sourc
|
||||||
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
||||||
|
|
||||||
### Compilation Troubleshooting
|
### Compilation Troubleshooting
|
||||||
If you ever encounter compilation issues during the updating of Pleroma, you can try these commands and see if they fix things:
|
If you ever encounter compilation issues during the updating of Akkoma, you can try these commands and see if they fix things:
|
||||||
|
|
||||||
- `mix deps.clean --all`
|
- `mix deps.clean --all`
|
||||||
- `mix local.rebar`
|
- `mix local.rebar`
|
||||||
|
|
|
@ -576,38 +576,6 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa
|
||||||
* Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared,
|
* Response: the archive of the pack with a 200 status code, 403 if the pack is not set as shared,
|
||||||
404 if the pack does not exist
|
404 if the pack does not exist
|
||||||
|
|
||||||
## `GET /api/v1/pleroma/accounts/:id/scrobbles`
|
|
||||||
### Requests a list of current and recent Listen activities for an account
|
|
||||||
* Method `GET`
|
|
||||||
* Authentication: not required
|
|
||||||
* Params: None
|
|
||||||
* Response: An array of media metadata entities.
|
|
||||||
* Example response:
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"account": {...},
|
|
||||||
"id": "1234",
|
|
||||||
"title": "Some Title",
|
|
||||||
"artist": "Some Artist",
|
|
||||||
"album": "Some Album",
|
|
||||||
"length": 180000,
|
|
||||||
"created_at": "2019-09-28T12:40:45.000Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## `POST /api/v1/pleroma/scrobble`
|
|
||||||
### Creates a new Listen activity for an account
|
|
||||||
* Method `POST`
|
|
||||||
* Authentication: required
|
|
||||||
* Params:
|
|
||||||
* `title`: the title of the media playing
|
|
||||||
* `album`: the album of the media playing [optional]
|
|
||||||
* `artist`: the artist of the media playing [optional]
|
|
||||||
* `length`: the length of the media playing [optional]
|
|
||||||
* Response: the newly created media metadata entity representing the Listen activity
|
|
||||||
|
|
||||||
# Emoji Reactions
|
# Emoji Reactions
|
||||||
|
|
||||||
Emoji reactions work a lot like favourites do. They make it possible to react to a post with a single emoji character. To detect the presence of this feature, you can check `pleroma_emoji_reactions` entry in the features list of nodeinfo.
|
Emoji reactions work a lot like favourites do. They make it possible to react to a post with a single emoji character. To detect the presence of this feature, you can check `pleroma_emoji_reactions` entry in the features list of nodeinfo.
|
||||||
|
|
|
@ -318,26 +318,6 @@ defp maybe_schedule_poll_notifications(activity) do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
|
|
||||||
def listen(%{to: to, actor: actor, context: context, object: object} = params) do
|
|
||||||
additional = params[:additional] || %{}
|
|
||||||
# only accept false as false value
|
|
||||||
local = !(params[:local] == false)
|
|
||||||
published = params[:published]
|
|
||||||
|
|
||||||
listen_data =
|
|
||||||
make_listen_data(
|
|
||||||
%{to: to, actor: actor, published: published, context: context, object: object},
|
|
||||||
additional
|
|
||||||
)
|
|
||||||
|
|
||||||
with {:ok, activity} <- insert(listen_data, local),
|
|
||||||
_ <- notify_and_stream(activity),
|
|
||||||
:ok <- maybe_federate(activity) do
|
|
||||||
{:ok, activity}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) ::
|
@spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) ::
|
||||||
{:ok, Activity.t()} | nil | {:error, any()}
|
{:ok, Activity.t()} | nil | {:error, any()}
|
||||||
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||||
|
|
|
@ -384,37 +384,6 @@ def handle_incoming(%{"id" => ""}, _options), do: :error
|
||||||
def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8,
|
def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8,
|
||||||
do: :error
|
do: :error
|
||||||
|
|
||||||
def handle_incoming(
|
|
||||||
%{"type" => "Listen", "object" => %{"type" => "Audio"} = object} = data,
|
|
||||||
options
|
|
||||||
) do
|
|
||||||
actor = Containment.get_actor(data)
|
|
||||||
|
|
||||||
data =
|
|
||||||
Map.put(data, "actor", actor)
|
|
||||||
|> fix_addressing
|
|
||||||
|
|
||||||
with {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
|
|
||||||
reply_depth = (options[:depth] || 0) + 1
|
|
||||||
options = Keyword.put(options, :depth, reply_depth)
|
|
||||||
object = fix_object(object, options)
|
|
||||||
|
|
||||||
params = %{
|
|
||||||
to: data["to"],
|
|
||||||
object: object,
|
|
||||||
actor: user,
|
|
||||||
context: nil,
|
|
||||||
local: false,
|
|
||||||
published: data["published"],
|
|
||||||
additional: Map.take(data, ["cc", "id"])
|
|
||||||
}
|
|
||||||
|
|
||||||
ActivityPub.listen(params)
|
|
||||||
else
|
|
||||||
_e -> :error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Rewrite misskey likes into EmojiReacts"
|
@doc "Rewrite misskey likes into EmojiReacts"
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{
|
%{
|
||||||
|
@ -695,7 +664,7 @@ def prepare_object(object) do
|
||||||
# """
|
# """
|
||||||
|
|
||||||
def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data)
|
def prepare_outgoing(%{"type" => activity_type, "object" => object_id} = data)
|
||||||
when activity_type in ["Create", "Listen"] do
|
when activity_type in ["Create"] do
|
||||||
object =
|
object =
|
||||||
object_id
|
object_id
|
||||||
|> Object.normalize(fetch: false)
|
|> Object.normalize(fetch: false)
|
||||||
|
|
|
@ -713,21 +713,6 @@ def make_create_data(params, additional) do
|
||||||
|> Map.merge(additional)
|
|> Map.merge(additional)
|
||||||
end
|
end
|
||||||
|
|
||||||
#### Listen-related helpers
|
|
||||||
def make_listen_data(params, additional) do
|
|
||||||
published = params.published || make_date()
|
|
||||||
|
|
||||||
%{
|
|
||||||
"type" => "Listen",
|
|
||||||
"to" => params.to |> Enum.uniq(),
|
|
||||||
"actor" => params.actor.ap_id,
|
|
||||||
"object" => params.object,
|
|
||||||
"published" => published,
|
|
||||||
"context" => params.context
|
|
||||||
}
|
|
||||||
|> Map.merge(additional)
|
|
||||||
end
|
|
||||||
|
|
||||||
#### Flag-related helpers
|
#### Flag-related helpers
|
||||||
@spec make_flag_data(map(), map()) :: map()
|
@spec make_flag_data(map(), map()) :: map()
|
||||||
def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do
|
def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do
|
||||||
|
|
|
@ -16,7 +16,7 @@ def render("object.json", %{object: %Object{} = object}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity})
|
def render("object.json", %{object: %Activity{data: %{"type" => activity_type}} = activity})
|
||||||
when activity_type in ["Create", "Listen"] do
|
when activity_type in ["Create"] do
|
||||||
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
|
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ def spec(opts \\ []) do
|
||||||
"x-tagGroups": [
|
"x-tagGroups": [
|
||||||
%{
|
%{
|
||||||
"name" => "Accounts",
|
"name" => "Accounts",
|
||||||
"tags" => ["Account actions", "Retrieve account information", "Scrobbles"]
|
"tags" => ["Account actions", "Retrieve account information"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"name" => "Administration",
|
"name" => "Administration",
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# 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
|
|
|
@ -388,12 +388,6 @@ def check_expiry_date(expiry_str) do
|
||||||
|> check_expiry_date()
|
|> check_expiry_date()
|
||||||
end
|
end
|
||||||
|
|
||||||
def listen(user, data) do
|
|
||||||
with {:ok, draft} <- ActivityDraft.listen(user, data) do
|
|
||||||
ActivityPub.listen(draft.changes)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def post(user, %{status: _} = data) do
|
def post(user, %{status: _} = data) do
|
||||||
with {:ok, draft} <- ActivityDraft.create(user, data) do
|
with {:ok, draft} <- ActivityDraft.create(user, data) do
|
||||||
ActivityPub.create(draft.changes, draft.preview?)
|
ActivityPub.create(draft.changes, draft.preview?)
|
||||||
|
|
|
@ -64,30 +64,6 @@ def create(user, params) do
|
||||||
|> validate()
|
|> validate()
|
||||||
end
|
end
|
||||||
|
|
||||||
def listen(user, params) do
|
|
||||||
user
|
|
||||||
|> new(params)
|
|
||||||
|> visibility()
|
|
||||||
|> to_and_cc()
|
|
||||||
|> context()
|
|
||||||
|> listen_object()
|
|
||||||
|> with_valid(&changes/1)
|
|
||||||
|> validate()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp listen_object(draft) do
|
|
||||||
object =
|
|
||||||
draft.params
|
|
||||||
|> Map.take([:album, :artist, :title, :length])
|
|
||||||
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|
|
||||||
|> Map.put("type", "Audio")
|
|
||||||
|> Map.put("to", draft.to)
|
|
||||||
|> Map.put("cc", draft.cc)
|
|
||||||
|> Map.put("actor", draft.user.ap_id)
|
|
||||||
|
|
||||||
%__MODULE__{draft | object: object}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp put_params(draft, params) do
|
defp put_params(draft, params) do
|
||||||
params = Map.put_new(params, :in_reply_to_status_id, params[:in_reply_to_id])
|
params = Map.put_new(params, :in_reply_to_status_id, params[:in_reply_to_id])
|
||||||
%__MODULE__{draft | params: params}
|
%__MODULE__{draft | params: params}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
|
|
||||||
use Pleroma.Web, :controller
|
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
|
||||||
alias Pleroma.Web.CommonAPI
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
|
||||||
|
|
||||||
plug(
|
|
||||||
OAuthScopesPlug,
|
|
||||||
%{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :index
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(OAuthScopesPlug, %{scopes: ["write"]} when action == :create)
|
|
||||||
|
|
||||||
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
|
|
||||||
render(conn, "show.json", activity: activity, for: user)
|
|
||||||
else
|
|
||||||
{:error, message} ->
|
|
||||||
conn
|
|
||||||
|> put_status(:bad_request)
|
|
||||||
|> json(%{"error" => message})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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 = Map.put(params, :type, ["Listen"])
|
|
||||||
|
|
||||||
activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params)
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> add_link_headers(activities)
|
|
||||||
|> render("index.json", %{
|
|
||||||
activities: activities,
|
|
||||||
for: reading_user,
|
|
||||||
as: :activity
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# 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
|
|
||||||
alias Pleroma.Web.CommonAPI.Utils
|
|
||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
|
||||||
|
|
||||||
def render("show.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
|
|
||||||
object = Object.normalize(activity, fetch: false)
|
|
||||||
|
|
||||||
user = CommonAPI.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
|
|
|
@ -447,8 +447,6 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/mascot", MascotController, :show)
|
get("/mascot", MascotController, :show)
|
||||||
put("/mascot", MascotController, :update)
|
put("/mascot", MascotController, :update)
|
||||||
|
|
||||||
post("/scrobble", ScrobbleController, :create)
|
|
||||||
|
|
||||||
get("/backups", BackupController, :index)
|
get("/backups", BackupController, :index)
|
||||||
post("/backups", BackupController, :create)
|
post("/backups", BackupController, :create)
|
||||||
end
|
end
|
||||||
|
@ -470,7 +468,6 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
||||||
pipe_through(:api)
|
pipe_through(:api)
|
||||||
get("/accounts/:id/scrobbles", ScrobbleController, :index)
|
|
||||||
get("/federation_status", InstancesController, :show)
|
get("/federation_status", InstancesController, :show)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -543,42 +543,6 @@ test "adds an id to a given object if it lacks one and is a note and inserts it
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "listen activities" do
|
|
||||||
test "does not increase user note count" do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity} =
|
|
||||||
ActivityPub.listen(%{
|
|
||||||
to: ["https://www.w3.org/ns/activitystreams#Public"],
|
|
||||||
actor: user,
|
|
||||||
context: "",
|
|
||||||
object: %{
|
|
||||||
"actor" => user.ap_id,
|
|
||||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
|
||||||
"artist" => "lain",
|
|
||||||
"title" => "lain radio episode 1",
|
|
||||||
"length" => 180_000,
|
|
||||||
"type" => "Audio"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
assert activity.actor == user.ap_id
|
|
||||||
|
|
||||||
user = User.get_cached_by_id(user.id)
|
|
||||||
assert user.note_count == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
test "can be fetched into a timeline" do
|
|
||||||
_listen_activity_1 = insert(:listen)
|
|
||||||
_listen_activity_2 = insert(:listen)
|
|
||||||
_listen_activity_3 = insert(:listen)
|
|
||||||
|
|
||||||
timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]})
|
|
||||||
|
|
||||||
assert length(timeline) == 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "create activities" do
|
describe "create activities" do
|
||||||
setup do
|
setup do
|
||||||
[user: insert(:user)]
|
[user: insert(:user)]
|
||||||
|
|
|
@ -12,39 +12,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
test "it works for incoming listens" do
|
|
||||||
_user = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
|
|
||||||
|
|
||||||
data = %{
|
|
||||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
|
||||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
|
||||||
"cc" => [],
|
|
||||||
"type" => "Listen",
|
|
||||||
"id" => "http://mastodon.example.org/users/admin/listens/1234/activity",
|
|
||||||
"actor" => "http://mastodon.example.org/users/admin",
|
|
||||||
"object" => %{
|
|
||||||
"type" => "Audio",
|
|
||||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
|
||||||
"cc" => [],
|
|
||||||
"id" => "http://mastodon.example.org/users/admin/listens/1234",
|
|
||||||
"attributedTo" => "http://mastodon.example.org/users/admin",
|
|
||||||
"title" => "lain radio episode 1",
|
|
||||||
"artist" => "lain",
|
|
||||||
"album" => "lain radio",
|
|
||||||
"length" => 180_000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
|
|
||||||
|
|
||||||
object = Object.normalize(activity, fetch: false)
|
|
||||||
|
|
||||||
assert object.data["title"] == "lain radio episode 1"
|
|
||||||
assert object.data["artist"] == "lain"
|
|
||||||
assert object.data["album"] == "lain radio"
|
|
||||||
assert object.data["length"] == 180_000
|
|
||||||
end
|
|
||||||
|
|
||||||
test "Funkwhale Audio object" do
|
test "Funkwhale Audio object" do
|
||||||
Tesla.Mock.mock(fn
|
Tesla.Mock.mock(fn
|
||||||
%{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} ->
|
%{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} ->
|
||||||
|
|
|
@ -273,20 +273,6 @@ test "it strips BCC field" do
|
||||||
assert is_nil(modified["bcc"])
|
assert is_nil(modified["bcc"])
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it can handle Listen activities" do
|
|
||||||
listen_activity = insert(:listen)
|
|
||||||
|
|
||||||
{:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
|
|
||||||
|
|
||||||
assert modified["type"] == "Listen"
|
|
||||||
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
|
|
||||||
|
|
||||||
{:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "custom emoji urls are URI encoded" do
|
test "custom emoji urls are URI encoded" do
|
||||||
# :dinosaur: filename has a space -> dino walking.gif
|
# :dinosaur: filename has a space -> dino walking.gif
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -1331,45 +1331,6 @@ test "does not allow to vote twice" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "listen/2" do
|
|
||||||
test "returns a valid activity" do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity} =
|
|
||||||
CommonAPI.listen(user, %{
|
|
||||||
title: "lain radio episode 1",
|
|
||||||
album: "lain radio",
|
|
||||||
artist: "lain",
|
|
||||||
length: 180_000
|
|
||||||
})
|
|
||||||
|
|
||||||
object = Object.normalize(activity, fetch: false)
|
|
||||||
|
|
||||||
assert object.data["title"] == "lain radio episode 1"
|
|
||||||
|
|
||||||
assert Visibility.get_visibility(activity) == "public"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "respects visibility=private" do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity} =
|
|
||||||
CommonAPI.listen(user, %{
|
|
||||||
title: "lain radio episode 1",
|
|
||||||
album: "lain radio",
|
|
||||||
artist: "lain",
|
|
||||||
length: 180_000,
|
|
||||||
visibility: "private"
|
|
||||||
})
|
|
||||||
|
|
||||||
object = Object.normalize(activity, fetch: false)
|
|
||||||
|
|
||||||
assert object.data["title"] == "lain radio episode 1"
|
|
||||||
|
|
||||||
assert Visibility.get_visibility(activity) == "private"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "get_user/1" do
|
describe "get_user/1" do
|
||||||
test "gets user by ap_id" do
|
test "gets user by ap_id" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do
|
|
||||||
use Pleroma.Web.ConnCase, async: true
|
|
||||||
|
|
||||||
alias Pleroma.Web.CommonAPI
|
|
||||||
|
|
||||||
describe "POST /api/v1/pleroma/scrobble" do
|
|
||||||
test "works correctly" do
|
|
||||||
%{conn: conn} = oauth_access(["write"])
|
|
||||||
|
|
||||||
conn =
|
|
||||||
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_and_validate_schema(conn, 200)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do
|
|
||||||
test "works correctly" do
|
|
||||||
%{user: user, conn: conn} = oauth_access(["read"])
|
|
||||||
|
|
||||||
{:ok, _activity} =
|
|
||||||
CommonAPI.listen(user, %{
|
|
||||||
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"
|
|
||||||
})
|
|
||||||
|
|
||||||
{:ok, _activity} =
|
|
||||||
CommonAPI.listen(user, %{
|
|
||||||
title: "lain radio episode 3",
|
|
||||||
artist: "lain",
|
|
||||||
album: "lain radio"
|
|
||||||
})
|
|
||||||
|
|
||||||
conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/scrobbles")
|
|
||||||
|
|
||||||
result = json_response_and_validate_schema(conn, 200)
|
|
||||||
|
|
||||||
assert length(result) == 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.PleromaAPI.ScrobbleViewTest do
|
|
||||||
use Pleroma.DataCase, async: true
|
|
||||||
|
|
||||||
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
|
|
Loading…
Reference in a new issue