Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into announce-validator

This commit is contained in:
lain 2020-05-20 14:02:40 +02:00
commit c7cdc553ff
579 changed files with 2044 additions and 1492 deletions

View File

@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **Breaking:** removed `with_move` parameter from notifications timeline. - **Breaking:** removed `with_move` parameter from notifications timeline.
### Added ### Added
- Instance: Add `background_image` to configuration and `/api/v1/instance`
- Instance: Extend `/api/v1/instance` with Pleroma-specific information. - Instance: Extend `/api/v1/instance` with Pleroma-specific information.
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list. - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` to the `features` list. - NodeInfo: `pleroma_emoji_reactions` to the `features` list.

View File

@ -123,7 +123,7 @@ def generate_tagged_activities(opts \\ []) do
Enum.each(1..activity_count, fn _ -> Enum.each(1..activity_count, fn _ ->
random = :rand.uniform() random = :rand.uniform()
i = Enum.find_index(intervals, fn {lower, upper} -> lower <= random && upper > random end) i = Enum.find_index(intervals, fn {lower, upper} -> lower <= random && upper > random end)
CommonAPI.post(Enum.random(users), %{"status" => "a post with the tag #tag_#{i}"}) CommonAPI.post(Enum.random(users), %{status: "a post with the tag #tag_#{i}"})
end) end)
end end
@ -137,8 +137,8 @@ defp generate_long_thread(visibility, user, friends, non_friends, _opts) do
{:ok, activity} = {:ok, activity} =
CommonAPI.post(user, %{ CommonAPI.post(user, %{
"status" => "Start of #{visibility} long thread", status: "Start of #{visibility} long thread",
"visibility" => visibility visibility: visibility
}) })
Agent.update(:benchmark_state, fn state -> Agent.update(:benchmark_state, fn state ->
@ -186,7 +186,7 @@ defp insert_activity("simple", visibility, group, user, friends, non_friends, _o
{:ok, _activity} = {:ok, _activity} =
group group
|> get_actor(user, friends, non_friends) |> get_actor(user, friends, non_friends)
|> CommonAPI.post(%{"status" => "Simple status", "visibility" => visibility}) |> CommonAPI.post(%{status: "Simple status", visibility: visibility})
end end
defp insert_activity("emoji", visibility, group, user, friends, non_friends, _opts) do defp insert_activity("emoji", visibility, group, user, friends, non_friends, _opts) do
@ -194,8 +194,8 @@ defp insert_activity("emoji", visibility, group, user, friends, non_friends, _op
group group
|> get_actor(user, friends, non_friends) |> get_actor(user, friends, non_friends)
|> CommonAPI.post(%{ |> CommonAPI.post(%{
"status" => "Simple status with emoji :firefox:", status: "Simple status with emoji :firefox:",
"visibility" => visibility visibility: visibility
}) })
end end
@ -213,8 +213,8 @@ defp insert_activity("mentions", visibility, group, user, friends, non_friends,
group group
|> get_actor(user, friends, non_friends) |> get_actor(user, friends, non_friends)
|> CommonAPI.post(%{ |> CommonAPI.post(%{
"status" => Enum.join(user_mentions, ", ") <> " simple status with mentions", status: Enum.join(user_mentions, ", ") <> " simple status with mentions",
"visibility" => visibility visibility: visibility
}) })
end end
@ -236,8 +236,8 @@ defp insert_activity("hell_thread", visibility, group, user, friends, non_friend
group group
|> get_actor(user, friends, non_friends) |> get_actor(user, friends, non_friends)
|> CommonAPI.post(%{ |> CommonAPI.post(%{
"status" => mentions <> " hell thread status", status: mentions <> " hell thread status",
"visibility" => visibility visibility: visibility
}) })
end end
@ -262,9 +262,9 @@ defp insert_activity("attachment", visibility, group, user, friends, non_friends
{:ok, _activity} = {:ok, _activity} =
CommonAPI.post(actor, %{ CommonAPI.post(actor, %{
"status" => "Post with attachment", status: "Post with attachment",
"visibility" => visibility, visibility: visibility,
"media_ids" => [object.id] media_ids: [object.id]
}) })
end end
@ -272,7 +272,7 @@ defp insert_activity("tag", visibility, group, user, friends, non_friends, _opts
{:ok, _activity} = {:ok, _activity} =
group group
|> get_actor(user, friends, non_friends) |> get_actor(user, friends, non_friends)
|> CommonAPI.post(%{"status" => "Status with #tag", "visibility" => visibility}) |> CommonAPI.post(%{status: "Status with #tag", visibility: visibility})
end end
defp insert_activity("like", visibility, group, user, friends, non_friends, opts) do defp insert_activity("like", visibility, group, user, friends, non_friends, opts) do
@ -312,8 +312,7 @@ defp insert_activity("simple_thread", visibility, group, user, friends, non_frie
actor = get_actor(group, user, friends, non_friends) actor = get_actor(group, user, friends, non_friends)
tasks = get_reply_tasks(visibility, group) tasks = get_reply_tasks(visibility, group)
{:ok, activity} = {:ok, activity} = CommonAPI.post(user, %{status: "Simple status", visibility: visibility})
CommonAPI.post(user, %{"status" => "Simple status", "visibility" => visibility})
acc = {activity.id, ["@" <> actor.nickname, "reply to status"]} acc = {activity.id, ["@" <> actor.nickname, "reply to status"]}
insert_replies(tasks, visibility, user, friends, non_friends, acc) insert_replies(tasks, visibility, user, friends, non_friends, acc)
@ -336,8 +335,8 @@ defp insert_activity("simple_thread", "direct", group, user, friends, non_friend
{:ok, activity} = {:ok, activity} =
CommonAPI.post(actor, %{ CommonAPI.post(actor, %{
"status" => Enum.join(data, ", ") <> "simple status", status: Enum.join(data, ", ") <> "simple status",
"visibility" => "direct" visibility: "direct"
}) })
acc = {activity.id, ["@" <> user.nickname | data] ++ ["reply to status"]} acc = {activity.id, ["@" <> user.nickname | data] ++ ["reply to status"]}
@ -527,9 +526,9 @@ defp insert_direct_replies(tasks, user, list, acc) do
defp insert_reply(actor, data, activity_id, visibility) do defp insert_reply(actor, data, activity_id, visibility) do
{:ok, reply} = {:ok, reply} =
CommonAPI.post(actor, %{ CommonAPI.post(actor, %{
"status" => Enum.join(data, ", "), status: Enum.join(data, ", "),
"visibility" => visibility, visibility: visibility,
"in_reply_to_status_id" => activity_id in_reply_to_status_id: activity_id
}) })
{reply.id, ["@" <> actor.nickname | data]} {reply.id, ["@" <> actor.nickname | data]}

View File

@ -183,6 +183,7 @@
email: "example@example.com", email: "example@example.com",
notify_email: "noreply@example.com", notify_email: "noreply@example.com",
description: "A Pleroma instance, an alternative fediverse server", description: "A Pleroma instance, an alternative fediverse server",
background_image: "/images/city.jpg",
limit: 5_000, limit: 5_000,
chat_limit: 5_000, chat_limit: 5_000,
remote_limit: 100_000, remote_limit: 100_000,
@ -376,6 +377,10 @@
config :pleroma, :media_proxy, config :pleroma, :media_proxy,
enabled: false, enabled: false,
invalidation: [
enabled: false,
provider: Pleroma.Web.MediaProxy.Invalidation.Script
],
proxy_opts: [ proxy_opts: [
redirect_on_failure: false, redirect_on_failure: false,
max_body_length: 25 * 1_048_576, max_body_length: 25 * 1_048_576,

View File

@ -216,6 +216,7 @@ Has theses additional parameters (which are the same as in Pleroma-API):
- `avatar_upload_limit`: The same for avatars - `avatar_upload_limit`: The same for avatars
- `background_upload_limit`: The same for backgrounds - `background_upload_limit`: The same for backgrounds
- `banner_upload_limit`: The same for banners - `banner_upload_limit`: The same for banners
- `background_image`: A background image that frontends can use
- `pleroma.metadata.features`: A list of supported features - `pleroma.metadata.features`: A list of supported features
- `pleroma.metadata.federation`: The federation restrictions of this instance - `pleroma.metadata.federation`: The federation restrictions of this instance
- `vapid_public_key`: The public key needed for push messages - `vapid_public_key`: The public key needed for push messages

View File

@ -265,7 +265,7 @@ See [Admin-API](admin_api.md)
* Method `PUT` * Method `PUT`
* Authentication: required * Authentication: required
* Params: * Params:
* `image`: Multipart image * `file`: Multipart image
* Response: JSON. Returns a mastodon media attachment entity * Response: JSON. Returns a mastodon media attachment entity
when successful, otherwise returns HTTP 415 `{"error": "error_msg"}` when successful, otherwise returns HTTP 415 `{"error": "error_msg"}`
* Example response: * Example response:

View File

@ -249,6 +249,40 @@ This section describe PWA manifest instance-specific values. Currently this opti
* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts. * `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.
* `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`. * `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`.
* `whitelist`: List of domains to bypass the mediaproxy * `whitelist`: List of domains to bypass the mediaproxy
* `invalidation`: options for remove media from cache after delete object:
* `enabled`: Enables purge cache
* `provider`: Which one of the [purge cache strategy](#purge-cache-strategy) to use.
### Purge cache strategy
#### Pleroma.Web.MediaProxy.Invalidation.Script
This strategy allow perform external bash script to purge cache.
Urls of attachments pass to script as arguments.
* `script_path`: path to external script.
Example:
```elixir
config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Script,
script_path: "./installation/nginx-cache-purge.example"
```
#### Pleroma.Web.MediaProxy.Invalidation.Http
This strategy allow perform custom http request to purge cache.
* `method`: http method. default is `purge`
* `headers`: http headers. default is empty
* `options`: request options. default is empty
Example:
```elixir
config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Http,
method: :purge,
headers: [],
options: []
```
## Link previews ## Link previews
@ -619,24 +653,6 @@ config :pleroma, :workers,
* `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]` * `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]`
* deprecated options: `max_jobs`, `initial_timeout` * deprecated options: `max_jobs`, `initial_timeout`
### Pleroma.Scheduler
Configuration for [Quantum](https://github.com/quantum-elixir/quantum-core) jobs scheduler.
See [Quantum readme](https://github.com/quantum-elixir/quantum-core#usage) for the list of supported options.
Example:
```elixir
config :pleroma, Pleroma.Scheduler,
global: true,
overlap: true,
timezone: :utc,
jobs: [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}]
```
The above example defines a single job which invokes `Pleroma.Web.Websub.refresh_subscriptions()` every 6 hours ("0 */6 * * * *", [crontab format](https://en.wikipedia.org/wiki/Cron)).
## :web_push_encryption, :vapid_details ## :web_push_encryption, :vapid_details
Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it. Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it.

View File

@ -0,0 +1,40 @@
#!/bin/sh
# A simple shell script to delete a media from the Nginx cache.
SCRIPTNAME=${0##*/}
# NGINX cache directory
CACHE_DIRECTORY="/tmp/pleroma-media-cache"
## Return the files where the items are cached.
## $1 - the filename, can be a pattern .
## $2 - the cache directory.
## $3 - (optional) the number of parallel processes to run for grep.
get_cache_files() {
local max_parallel=${3-16}
find $2 -maxdepth 2 -type d | xargs -P $max_parallel -n 1 grep -E Rl "^KEY:.*$1" | sort -u
}
## Removes an item from the given cache zone.
## $1 - the filename, can be a pattern .
## $2 - the cache directory.
purge_item() {
for f in $(get_cache_files $1 $2); do
echo "found file: $f"
[ -f $f ] || continue
echo "Deleting $f from $2."
rm $f
done
} # purge_item
purge() {
for url in "$@"
do
echo "$SCRIPTNAME delete \`$url\` from cache ($CACHE_DIRECTORY)"
purge_item $url $CACHE_DIRECTORY
done
}
purge $1

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA do defmodule Pleroma.MFA do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA.BackupCodes do defmodule Pleroma.MFA.BackupCodes do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA.Changeset do defmodule Pleroma.MFA.Changeset do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA.Settings do defmodule Pleroma.MFA.Settings do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA.Token do defmodule Pleroma.MFA.Token do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFA.TOTP do defmodule Pleroma.MFA.TOTP do

View File

@ -9,11 +9,13 @@ defmodule Pleroma.Object do
import Ecto.Changeset import Ecto.Changeset
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Fetcher alias Pleroma.Object.Fetcher
alias Pleroma.ObjectTombstone alias Pleroma.ObjectTombstone
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
alias Pleroma.Workers.AttachmentsCleanupWorker
require Logger require Logger
@ -188,27 +190,37 @@ def swap_object_with_tombstone(object) do
def delete(%Object{data: %{"id" => id}} = object) do def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object), with {:ok, _obj} = swap_object_with_tombstone(object),
deleted_activity = Activity.delete_all_by_object_ap_id(id), deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- invalid_object_cache(object) do
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do cleanup_attachments(
with true <- Pleroma.Config.get([:instance, :cleanup_attachments]) do Config.get([:instance, :cleanup_attachments]),
{:ok, _} = %{"object" => object}
Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{ )
"object" => object
})
end
{:ok, object, deleted_activity} {:ok, object, deleted_activity}
end end
end end
def prune(%Object{data: %{"id" => id}} = object) do @spec cleanup_attachments(boolean(), %{required(:object) => map()}) ::
{:ok, Oban.Job.t() | nil}
def cleanup_attachments(true, %{"object" => _} = params) do
AttachmentsCleanupWorker.enqueue("cleanup_attachments", params)
end
def cleanup_attachments(_, _), do: {:ok, nil}
def prune(%Object{data: %{"id" => _id}} = object) do
with {:ok, object} <- Repo.delete(object), with {:ok, object} <- Repo.delete(object),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- invalid_object_cache(object) do
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
{:ok, object} {:ok, object}
end end
end end
def invalid_object_cache(%Object{data: %{"id" => id}}) do
with {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
Cachex.del(:web_resp_cache, URI.parse(id).path)
end
end
def set_cache(%Object{data: %{"id" => ap_id}} = object) do def set_cache(%Object{data: %{"id" => ap_id}} = object) do
Cachex.put(:object_cache, "object:#{ap_id}", object) Cachex.put(:object_cache, "object:#{ap_id}", object)
{:ok, object} {:ok, object}

View File

@ -1204,7 +1204,9 @@ def get_users_from_set(ap_ids, local_only \\ true) do
def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do
to = [actor | to] to = [actor | to]
User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false}) query = User.Query.build(%{recipients_from_activity: to, local: true, deactivated: false})
query
|> Repo.all() |> Repo.all()
end end
@ -1430,6 +1432,25 @@ def delete(%User{} = user) do
BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id}) BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
end end
defp delete_and_invalidate_cache(%User{} = user) do
invalidate_cache(user)
Repo.delete(user)
end
defp delete_or_deactivate(%User{local: false} = user), do: delete_and_invalidate_cache(user)
defp delete_or_deactivate(%User{local: true} = user) do
status = account_status(user)
if status == :confirmation_pending do
delete_and_invalidate_cache(user)
else
user
|> change(%{deactivated: true, email: nil})
|> update_and_set_cache()
end
end
def perform(:force_password_reset, user), do: force_password_reset(user) def perform(:force_password_reset, user), do: force_password_reset(user)
@spec perform(atom(), User.t()) :: {:ok, User.t()} @spec perform(atom(), User.t()) :: {:ok, User.t()}
@ -1451,14 +1472,7 @@ def perform(:delete, %User{} = user) do
delete_user_activities(user) delete_user_activities(user)
if user.local do delete_or_deactivate(user)
user
|> change(%{deactivated: true, email: nil})
|> update_and_set_cache()
else
invalidate_cache(user)
Repo.delete(user)
end
end end
def perform(:deactivate_async, user, status), do: deactivate(user, status) def perform(:deactivate_async, user, status), do: deactivate(user, status)

View File

@ -167,20 +167,18 @@ defp compose_query({:friends, %User{id: id}}, query) do
end end
defp compose_query({:recipients_from_activity, to}, query) do defp compose_query({:recipients_from_activity, to}, query) do
query following_query =
|> join(:left, [u], r in FollowingRelationship, from(u in User,
as: :relationships, join: f in FollowingRelationship,
on: r.follower_id == u.id on: u.id == f.following_id,
where: f.state == ^:follow_accept,
where: u.follower_address in ^to,
select: f.follower_id
) )
|> join(:left, [relationships: r], f in User,
as: :following, from(u in query,
on: f.id == r.following_id where: u.ap_id in ^to or u.id in subquery(following_query)
) )
|> where(
[u, following: f, relationships: r],
u.ap_id in ^to or (f.follower_address in ^to and r.state == ^:follow_accept)
)
|> distinct(true)
end end
defp compose_query({:order_by, key}, query) do defp compose_query({:order_by, key}, query) do

View File

@ -393,7 +393,7 @@ defp create_request do
format: :password format: :password
}, },
agreement: %Schema{ agreement: %Schema{
type: :boolean, allOf: [BooleanLike],
description: description:
"Whether the user agrees to the local rules, terms, and policies. These should be presented to the user in order to allow them to consent before setting this parameter to TRUE." "Whether the user agrees to the local rules, terms, and policies. These should be presented to the user in order to allow them to consent before setting this parameter to TRUE."
}, },
@ -463,7 +463,7 @@ defp update_creadentials_request do
type: :object, type: :object,
properties: %{ properties: %{
bot: %Schema{ bot: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Whether the account has a bot flag." description: "Whether the account has a bot flag."
}, },
@ -486,7 +486,7 @@ defp update_creadentials_request do
format: :binary format: :binary
}, },
locked: %Schema{ locked: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Whether manual approval of follow requests is required." description: "Whether manual approval of follow requests is required."
}, },
@ -510,37 +510,37 @@ defp update_creadentials_request do
# Pleroma-specific fields # Pleroma-specific fields
no_rich_text: %Schema{ no_rich_text: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "html tags are stripped from all statuses requested from the API" description: "html tags are stripped from all statuses requested from the API"
}, },
hide_followers: %Schema{ hide_followers: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's followers will be hidden" description: "user's followers will be hidden"
}, },
hide_follows: %Schema{ hide_follows: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's follows will be hidden" description: "user's follows will be hidden"
}, },
hide_followers_count: %Schema{ hide_followers_count: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's follower count will be hidden" description: "user's follower count will be hidden"
}, },
hide_follows_count: %Schema{ hide_follows_count: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's follow count will be hidden" description: "user's follow count will be hidden"
}, },
hide_favorites: %Schema{ hide_favorites: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's favorites timeline will be hidden" description: "user's favorites timeline will be hidden"
}, },
show_role: %Schema{ show_role: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "user's role (e.g admin, moderator) will be exposed to anyone in the description: "user's role (e.g admin, moderator) will be exposed to anyone in the
API" API"
@ -552,12 +552,12 @@ defp update_creadentials_request do
description: "Opaque user settings to be saved on the backend." description: "Opaque user settings to be saved on the backend."
}, },
skip_thread_containment: %Schema{ skip_thread_containment: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Skip filtering out broken threads" description: "Skip filtering out broken threads"
}, },
allow_following_move: %Schema{ allow_following_move: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Allows automatically follow moved following accounts" description: "Allows automatically follow moved following accounts"
}, },
@ -568,7 +568,7 @@ defp update_creadentials_request do
format: :binary format: :binary
}, },
discoverable: %Schema{ discoverable: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: description:
"Discovery of this account in search results and other services is allowed." "Discovery of this account in search results and other services is allowed."
@ -678,7 +678,7 @@ defp mute_request do
type: :object, type: :object,
properties: %{ properties: %{
notifications: %Schema{ notifications: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Mute notifications in addition to statuses? Defaults to true.", description: "Mute notifications in addition to statuses? Defaults to true.",
default: true default: true

View File

@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do
alias OpenApiSpex.Operation alias OpenApiSpex.Operation
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def open_api_operation(action) do def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation") operation = String.to_existing_atom("#{action}_operation")
@ -171,7 +172,7 @@ defp create_request do
type: :object, type: :object,
properties: %{ properties: %{
irreversible: %Schema{ irreversible: %Schema{
type: :bolean, allOf: [BooleanLike],
description: description:
"Should the server irreversibly drop matching entities from home and notifications?", "Should the server irreversibly drop matching entities from home and notifications?",
default: false default: false
@ -199,13 +200,13 @@ defp update_request do
"Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified." "Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified."
}, },
irreversible: %Schema{ irreversible: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: description:
"Should the server irreversibly drop matching entities from home and notifications?" "Should the server irreversibly drop matching entities from home and notifications?"
}, },
whole_word: %Schema{ whole_word: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Consider word boundaries?", description: "Consider word boundaries?",
default: true default: true

View File

@ -125,11 +125,17 @@ defp instance do
}, },
avatar_upload_limit: %Schema{type: :integer, description: "The title of the website"}, avatar_upload_limit: %Schema{type: :integer, description: "The title of the website"},
background_upload_limit: %Schema{type: :integer, description: "The title of the website"}, background_upload_limit: %Schema{type: :integer, description: "The title of the website"},
banner_upload_limit: %Schema{type: :integer, description: "The title of the website"} banner_upload_limit: %Schema{type: :integer, description: "The title of the website"},
background_image: %Schema{
type: :string,
format: :uri,
description: "The background image for the website"
}
}, },
example: %{ example: %{
"avatar_upload_limit" => 2_000_000, "avatar_upload_limit" => 2_000_000,
"background_upload_limit" => 4_000_000, "background_upload_limit" => 4_000_000,
"background_image" => "/static/image.png",
"banner_upload_limit" => 4_000_000, "banner_upload_limit" => 4_000_000,
"description" => "A Pleroma instance, an alternative fediverse server", "description" => "A Pleroma instance, an alternative fediverse server",
"email" => "lain@lain.com", "email" => "lain@lain.com",

View File

@ -0,0 +1,79 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.PleromaMascotOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
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 show_operation do
%Operation{
tags: ["Mascot"],
summary: "Gets user mascot image",
security: [%{"oAuth" => ["read:accounts"]}],
operationId: "PleromaAPI.MascotController.show",
responses: %{
200 => Operation.response("Mascot", "application/json", mascot())
}
}
end
def update_operation do
%Operation{
tags: ["Mascot"],
summary: "Set/clear user avatar image",
description:
"Behaves exactly the same as `POST /api/v1/upload`. Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.",
operationId: "PleromaAPI.MascotController.update",
requestBody:
request_body(
"Parameters",
%Schema{
type: :object,
properties: %{
file: %Schema{type: :string, format: :binary}
}
},
required: true
),
security: [%{"oAuth" => ["write:accounts"]}],
responses: %{
200 => Operation.response("Mascot", "application/json", mascot()),
415 => Operation.response("Unsupported Media Type", "application/json", ApiError)
}
}
end
defp mascot do
%Schema{
type: :object,
properties: %{
id: %Schema{type: :string},
url: %Schema{type: :string, format: :uri},
type: %Schema{type: :string},
pleroma: %Schema{
type: :object,
properties: %{
mime_type: %Schema{type: :string}
}
}
},
example: %{
"id" => "abcdefg",
"url" => "https://pleroma.example.org/media/abcdefg.png",
"type" => "image",
"pleroma" => %{
"mime_type" => "image/png"
}
}
}
end
end

View File

@ -0,0 +1,102 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 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

View File

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def open_api_operation(action) do def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation") operation = String.to_existing_atom("#{action}_operation")
@ -47,7 +48,7 @@ defp create_request do
description: "Reason for the report" description: "Reason for the report"
}, },
forward: %Schema{ forward: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
default: false, default: false,
description: description:

View File

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.AccountOperation alias Pleroma.Web.ApiSpec.AccountOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
alias Pleroma.Web.ApiSpec.Schemas.Status alias Pleroma.Web.ApiSpec.Schemas.Status
@ -394,12 +395,12 @@ defp create_request do
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`" "Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
}, },
multiple: %Schema{ multiple: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Allow multiple choices?" description: "Allow multiple choices?"
}, },
hide_totals: %Schema{ hide_totals: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Hide vote counts until the poll ends?" description: "Hide vote counts until the poll ends?"
} }
@ -411,7 +412,7 @@ defp create_request do
description: "ID of the status being replied to, if status is a reply" description: "ID of the status being replied to, if status is a reply"
}, },
sensitive: %Schema{ sensitive: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Mark status and attached media as sensitive?" description: "Mark status and attached media as sensitive?"
}, },
@ -435,7 +436,7 @@ defp create_request do
}, },
# Pleroma-specific properties: # Pleroma-specific properties:
preview: %Schema{ preview: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: description:
"If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example" "If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"

View File

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.PushSubscription alias Pleroma.Web.ApiSpec.Schemas.PushSubscription
def open_api_operation(action) do def open_api_operation(action) do
@ -117,27 +118,27 @@ defp create_request do
type: :object, type: :object,
properties: %{ properties: %{
follow: %Schema{ follow: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive follow notifications?" description: "Receive follow notifications?"
}, },
favourite: %Schema{ favourite: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive favourite notifications?" description: "Receive favourite notifications?"
}, },
reblog: %Schema{ reblog: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive reblog notifications?" description: "Receive reblog notifications?"
}, },
mention: %Schema{ mention: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive mention notifications?" description: "Receive mention notifications?"
}, },
poll: %Schema{ poll: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive poll notifications?" description: "Receive poll notifications?"
} }
@ -181,27 +182,27 @@ defp update_request do
type: :object, type: :object,
properties: %{ properties: %{
follow: %Schema{ follow: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive follow notifications?" description: "Receive follow notifications?"
}, },
favourite: %Schema{ favourite: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive favourite notifications?" description: "Receive favourite notifications?"
}, },
reblog: %Schema{ reblog: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive reblog notifications?" description: "Receive reblog notifications?"
}, },
mention: %Schema{ mention: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive mention notifications?" description: "Receive mention notifications?"
}, },
poll: %Schema{ poll: %Schema{
type: :boolean, allOf: [BooleanLike],
nullable: true, nullable: true,
description: "Receive poll notifications?" description: "Receive poll notifications?"
} }

View File

@ -43,7 +43,7 @@ def direct_operation do
description: description:
"View statuses with a “direct” privacy, from your account or in your notifications", "View statuses with a “direct” privacy, from your account or in your notifications",
deprecated: true, deprecated: true,
parameters: pagination_params(), parameters: [with_muted_param() | pagination_params()],
security: [%{"oAuth" => ["read:statuses"]}], security: [%{"oAuth" => ["read:statuses"]}],
operationId: "TimelineController.direct", operationId: "TimelineController.direct",
responses: %{ responses: %{

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.TOTPAuthenticator do defmodule Pleroma.Web.Auth.TOTPAuthenticator do

View File

@ -347,11 +347,14 @@ def check_expiry_date(expiry_str) do
|> check_expiry_date() |> check_expiry_date()
end end
def listen(user, %{"title" => _} = data) do def listen(user, data) do
with visibility <- data["visibility"] || "public", visibility = Map.get(data, :visibility, "public")
{to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
with {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
listen_data <- 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("type", "Audio")
|> Map.put("to", to) |> Map.put("to", to)
|> Map.put("cc", cc) |> Map.put("cc", cc)

View File

@ -177,6 +177,7 @@ def update_credentials(%{assigns: %{user: original_user}, body_params: params} =
) )
|> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store) |> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store)
|> add_if_present(params, :default_scope, :default_scope) |> add_if_present(params, :default_scope, :default_scope)
|> add_if_present(params["source"], "privacy", :default_scope)
|> add_if_present(params, :actor_type, :actor_type) |> add_if_present(params, :actor_type, :actor_type)
changeset = User.update_changeset(user, user_params) changeset = User.update_changeset(user, user_params)
@ -189,7 +190,8 @@ def update_credentials(%{assigns: %{user: original_user}, body_params: params} =
end end
defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do
with true <- Map.has_key?(params, params_field), with true <- is_map(params),
true <- Map.has_key?(params, params_field),
{:ok, new_value} <- value_function.(Map.get(params, params_field)) do {:ok, new_value} <- value_function.(Map.get(params, params_field)) do
Map.put(map, map_field, new_value) Map.put(map, map_field, new_value)
else else

View File

@ -33,6 +33,7 @@ def render("show.json", _) do
avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit), avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),
background_upload_limit: Keyword.get(instance, :background_upload_limit), background_upload_limit: Keyword.get(instance, :background_upload_limit),
banner_upload_limit: Keyword.get(instance, :banner_upload_limit), banner_upload_limit: Keyword.get(instance, :banner_upload_limit),
background_image: Keyword.get(instance, :background_image),
pleroma: %{ pleroma: %{
metadata: %{ metadata: %{
features: features(), features: features(),

View File

@ -436,27 +436,6 @@ def render("attachment.json", %{attachment: attachment}) do
} }
end 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 def render("context.json", %{activity: activity, activities: activities, user: user}) do
%{ancestors: ancestors, descendants: descendants} = %{ancestors: ancestors, descendants: descendants} =
activities activities

View File

@ -0,0 +1,26 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxy.Invalidation do
@moduledoc false
@callback purge(list(String.t()), map()) :: {:ok, String.t()} | {:error, String.t()}
alias Pleroma.Config
@spec purge(list(String.t())) :: {:ok, String.t()} | {:error, String.t()}
def purge(urls) do
[:media_proxy, :invalidation, :enabled]
|> Config.get()
|> do_purge(urls)
end
defp do_purge(true, urls) do
provider = Config.get([:media_proxy, :invalidation, :provider])
options = Config.get(provider)
provider.purge(urls, options)
end
defp do_purge(_, _), do: :ok
end

View File

@ -0,0 +1,40 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxy.Invalidation.Http do
@moduledoc false
@behaviour Pleroma.Web.MediaProxy.Invalidation
require Logger
@impl Pleroma.Web.MediaProxy.Invalidation
def purge(urls, opts) do
method = Map.get(opts, :method, :purge)
headers = Map.get(opts, :headers, [])
options = Map.get(opts, :options, [])
Logger.debug("Running cache purge: #{inspect(urls)}")
Enum.each(urls, fn url ->
with {:error, error} <- do_purge(method, url, headers, options) do
Logger.error("Error while cache purge: url - #{url}, error: #{inspect(error)}")
end
end)
{:ok, "success"}
end
defp do_purge(method, url, headers, options) do
case Pleroma.HTTP.request(method, url, "", headers, options) do
{:ok, %{status: status} = env} when 400 <= status and status < 500 ->
{:error, env}
{:error, error} = error ->
error
_ ->
{:ok, "success"}
end
end
end

View File

@ -0,0 +1,41 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxy.Invalidation.Script do
@moduledoc false
@behaviour Pleroma.Web.MediaProxy.Invalidation
require Logger
@impl Pleroma.Web.MediaProxy.Invalidation
def purge(urls, %{script_path: script_path} = _options) do
args =
urls
|> List.wrap()
|> Enum.uniq()
|> Enum.join(" ")
path = Path.expand(script_path)
Logger.debug("Running cache purge: #{inspect(urls)}, #{path}")
case do_purge(path, [args]) do
{result, exit_status} when exit_status > 0 ->
Logger.error("Error while cache purge: #{inspect(result)}")
{:error, inspect(result)}
_ ->
{:ok, "success"}
end
end
def purge(_, _), do: {:error, "not found script path"}
defp do_purge(path, args) do
System.cmd(path, args)
rescue
error -> {inspect(error), 1}
end
end

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAController do defmodule Pleroma.Web.OAuth.MFAController do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAView do defmodule Pleroma.Web.OAuth.MFAView do

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.CleanWorker do defmodule Pleroma.Web.OAuth.Token.CleanWorker do

View File

@ -9,16 +9,19 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show) plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show) plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaMascotOperation
@doc "GET /api/v1/pleroma/mascot" @doc "GET /api/v1/pleroma/mascot"
def show(%{assigns: %{user: user}} = conn, _params) do def show(%{assigns: %{user: user}} = conn, _params) do
json(conn, User.get_mascot(user)) json(conn, User.get_mascot(user))
end end
@doc "PUT /api/v1/pleroma/mascot" @doc "PUT /api/v1/pleroma/mascot"
def update(%{assigns: %{user: user}} = conn, %{"file" => file}) do def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do
with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)),
# Reject if not an image # Reject if not an image
%{type: "image"} = attachment <- render_attachment(object) do %{type: "image"} = attachment <- render_attachment(object) do

View File

@ -5,34 +5,27 @@
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
use Pleroma.Web, :controller 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.Plugs.OAuthScopesPlug
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.StatusView
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug( plug(
OAuthScopesPlug, 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 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaScrobbleOperation
params =
if !params["length"] do
params
else
params
|> Map.put("length", fetch_integer_param(params, "length"))
end
def create(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, activity} <- CommonAPI.listen(user, params) do with {:ok, activity} <- CommonAPI.listen(user, params) do
conn render(conn, "show.json", activity: activity, for: user)
|> put_view(StatusView)
|> render("listen.json", %{activity: activity, for: user})
else else
{:error, message} -> {:error, message} ->
conn conn
@ -41,16 +34,18 @@ def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do
end end
end end
def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do def index(%{assigns: %{user: reading_user}} = conn, %{id: id} = params) do
with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do with %User{} = user <- User.get_cached_by_nickname_or_id(id, for: reading_user) do
params = Map.put(params, "type", ["Listen"]) 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) activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params)
conn conn
|> add_link_headers(activities) |> add_link_headers(activities)
|> put_view(StatusView) |> render("index.json", %{
|> render("listens.json", %{
activities: activities, activities: activities,
for: reading_user, for: reading_user,
as: :activity as: :activity

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationController do defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationController do

View File

@ -0,0 +1,37 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 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.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

View File

@ -325,7 +325,7 @@ defmodule Pleroma.Web.Router do
get("/mascot", MascotController, :show) get("/mascot", MascotController, :show)
put("/mascot", MascotController, :update) put("/mascot", MascotController, :update)
post("/scrobble", ScrobbleController, :new_scrobble) post("/scrobble", ScrobbleController, :create)
end end
scope [] do scope [] do
@ -345,7 +345,7 @@ 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, :user_scrobbles) get("/accounts/:id/scrobbles", ScrobbleController, :index)
end end
scope "/api/v1", Pleroma.Web.MastodonAPI do scope "/api/v1", Pleroma.Web.MastodonAPI do

View File

@ -27,8 +27,20 @@ def perform(
uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
prefix =
case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
nil -> "media"
_ -> ""
end
base_url =
String.trim_trailing(
Pleroma.Config.get([Pleroma.Upload, :base_url], Pleroma.Web.base_url()),
"/"
)
# find all objects for copies of the attachments, name and actor doesn't matter here # find all objects for copies of the attachments, name and actor doesn't matter here
delete_ids = object_ids_and_hrefs =
from(o in Object, from(o in Object,
where: where:
fragment( fragment(
@ -67,29 +79,28 @@ def perform(
|> Enum.map(fn {href, %{id: id, count: count}} -> |> Enum.map(fn {href, %{id: id, count: count}} ->
# only delete files that have single instance # only delete files that have single instance
with 1 <- count do with 1 <- count do
prefix = href
case Pleroma.Config.get([Pleroma.Upload, :base_url]) do |> String.trim_leading("#{base_url}/#{prefix}")
nil -> "media" |> uploader.delete_file()
_ -> ""
{id, href}
else
_ -> {id, nil}
end end
base_url =
String.trim_trailing(
Pleroma.Config.get([Pleroma.Upload, :base_url], Pleroma.Web.base_url()),
"/"
)
file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
uploader.delete_file(file_path)
end
id
end) end)
from(o in Object, where: o.id in ^delete_ids) object_ids = Enum.map(object_ids_and_hrefs, fn {id, _} -> id end)
from(o in Object, where: o.id in ^object_ids)
|> Repo.delete_all() |> Repo.delete_all()
object_ids_and_hrefs
|> Enum.filter(fn {_, href} -> not is_nil(href) end)
|> Enum.map(&elem(&1, 1))
|> Pleroma.Web.MediaProxy.Invalidation.purge()
{:ok, :success}
end end
def perform(%{"op" => "cleanup_attachments", "object" => _object}, _job), do: :ok def perform(%{"op" => "cleanup_attachments", "object" => _object}, _job), do: {:ok, :skip}
end end

View File

@ -155,7 +155,7 @@ defp deps do
{:credo, "~> 1.1.0", only: [:dev, :test], runtime: false}, {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
{:mock, "~> 0.3.3", only: :test}, {:mock, "~> 0.3.3", only: :test},
{:crypt, {:crypt,
git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"}, git: "https://github.com/msantos/crypt", ref: "f63a705f92c26955977ee62a313012e309a4d77a"},
{:cors_plug, "~> 1.5"}, {:cors_plug, "~> 1.5"},
{:ex_doc, "~> 0.21", only: :dev, runtime: false}, {:ex_doc, "~> 0.21", only: :dev, runtime: false},
{:web_push_encryption, "~> 0.2.1"}, {:web_push_encryption, "~> 0.2.1"},

View File

@ -21,13 +21,13 @@
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"}, "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
"credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"}, "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, "crypt": {:git, "https://github.com/msantos/crypt", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
"db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "2b02ece62d9f983fcd40954e443b7d9e6589664380e5546b2b9b523cd0fb59e1"}, "db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "2b02ece62d9f983fcd40954e443b7d9e6589664380e5546b2b9b523cd0fb59e1"},
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"ecto": {:hex, :ecto, "3.4.0", "a7a83ab8359bf816ce729e5e65981ce25b9fc5adfc89c2ea3980f4fed0bfd7c1", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "5eed18252f5b5bbadec56a24112b531343507dbe046273133176b12190ce19cc"}, "ecto": {:hex, :ecto, "3.4.4", "a2c881e80dc756d648197ae0d936216c0308370332c5e77a2325a10293eef845", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4bd3ad62abc3b21fb629f0f7a3dab23a192fca837d257dd08449fba7373561"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"}, "ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
@ -57,7 +57,7 @@
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"}, "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"}, "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"}, "jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
"joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"}, "joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "b4f92e30388206f869dd25d1af628a1d99d7586e5cf0672f64d4df84c4d2f5e9"},
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"}, "jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -4,103 +4,69 @@
http://jedwatson.github.io/classnames http://jedwatson.github.io/classnames
*/ */
/*!
* escape-html
* Copyright(c) 2012-2013 TJ Holowaychuk
* Copyright(c) 2015 Andreas Lubbe
* Copyright(c) 2015 Tiancheng "Timothy" Gu
* MIT Licensed
*/
/*! /*!
* wavesurfer.js 3.3.1 (2020-01-14) * wavesurfer.js 3.3.1 (2020-01-14)
* https://github.com/katspaugh/wavesurfer.js * https://github.com/katspaugh/wavesurfer.js
* @license BSD-3-Clause * @license BSD-3-Clause
*/ */
/*!****************************************!*\ /*! ./ajax */
!*** ./node_modules/debounce/index.js ***!
\****************************************/
/*! no static exports found */
/*!***********************************!*\
!*** ./src/drawer.canvasentry.js ***!
\***********************************/
/*! ./util/style */
/*! ./util/get-id */
/*!***********************!*\
!*** ./src/drawer.js ***!
\***********************/
/*! ./util */
/*!***********************************!*\
!*** ./src/drawer.multicanvas.js ***!
\***********************************/
/*! ./drawer */ /*! ./drawer */
/*! ./drawer.canvasentry */ /*! ./drawer.canvasentry */
/*!**************************************!*\ /*! ./drawer.multicanvas */
!*** ./src/mediaelement-webaudio.js ***!
\**************************************/
/*! ./mediaelement */ /*! ./extend */
/*!*****************************!*\ /*! ./fetch */
!*** ./src/mediaelement.js ***!
\*****************************/
/*! ./webaudio */ /*! ./frame */
/*!**************************!*\
!*** ./src/peakcache.js ***!
\**************************/
/*!**************************!*\
!*** ./src/util/ajax.js ***!
\**************************/
/*! ./observer */
/*!****************************!*\
!*** ./src/util/extend.js ***!
\****************************/
/*!***************************!*\
!*** ./src/util/fetch.js ***!
\***************************/
/*!***************************!*\
!*** ./src/util/frame.js ***!
\***************************/
/*! ./request-animation-frame */
/*!****************************!*\
!*** ./src/util/get-id.js ***!
\****************************/
/*!***************************!*\
!*** ./src/util/index.js ***!
\***************************/
/*! ./ajax */
/*! ./get-id */ /*! ./get-id */
/*! ./max */ /*! ./max */
/*! ./mediaelement */
/*! ./mediaelement-webaudio */
/*! ./min */ /*! ./min */
/*! ./extend */ /*! ./observer */
/*! ./style */ /*! ./peakcache */
/*! ./frame */
/*! debounce */
/*! ./prevent-click */ /*! ./prevent-click */
/*! ./fetch */ /*! ./request-animation-frame */
/*! ./style */
/*! ./util */
/*! ./util/get-id */
/*! ./util/style */
/*! ./webaudio */
/*! debounce */
/*! no static exports found */
/*!***********************!*\
!*** ./src/drawer.js ***!
\***********************/
/*!*************************!*\ /*!*************************!*\
!*** ./src/util/max.js ***! !*** ./src/util/max.js ***!
@ -110,17 +76,29 @@
!*** ./src/util/min.js ***! !*** ./src/util/min.js ***!
\*************************/ \*************************/
/*!******************************!*\ /*!*************************!*\
!*** ./src/util/observer.js ***! !*** ./src/webaudio.js ***!
\******************************/ \*************************/
/*!***********************************!*\ /*!**************************!*\
!*** ./src/util/prevent-click.js ***! !*** ./src/peakcache.js ***!
\***********************************/ \**************************/
/*!*********************************************!*\ /*!**************************!*\
!*** ./src/util/request-animation-frame.js ***! !*** ./src/util/ajax.js ***!
\*********************************************/ \**************************/
/*!***************************!*\
!*** ./src/util/fetch.js ***!
\***************************/
/*!***************************!*\
!*** ./src/util/frame.js ***!
\***************************/
/*!***************************!*\
!*** ./src/util/index.js ***!
\***************************/
/*!***************************!*\ /*!***************************!*\
!*** ./src/util/style.js ***! !*** ./src/util/style.js ***!
@ -130,20 +108,42 @@
!*** ./src/wavesurfer.js ***! !*** ./src/wavesurfer.js ***!
\***************************/ \***************************/
/*! ./drawer.multicanvas */ /*!****************************!*\
!*** ./src/util/extend.js ***!
\****************************/
/*! ./peakcache */ /*!****************************!*\
!*** ./src/util/get-id.js ***!
\****************************/
/*! ./mediaelement-webaudio */ /*!*****************************!*\
!*** ./src/mediaelement.js ***!
\*****************************/
/*!*************************!*\ /*!******************************!*\
!*** ./src/webaudio.js ***! !*** ./src/util/observer.js ***!
\*************************/ \******************************/
/*! /*!***********************************!*\
* escape-html !*** ./src/drawer.canvasentry.js ***!
* Copyright(c) 2012-2013 TJ Holowaychuk \***********************************/
* Copyright(c) 2015 Andreas Lubbe
* Copyright(c) 2015 Tiancheng "Timothy" Gu /*!***********************************!*\
* MIT Licensed !*** ./src/drawer.multicanvas.js ***!
*/ \***********************************/
/*!***********************************!*\
!*** ./src/util/prevent-click.js ***!
\***********************************/
/*!**************************************!*\
!*** ./src/mediaelement-webaudio.js ***!
\**************************************/
/*!****************************************!*\
!*** ./node_modules/debounce/index.js ***!
\****************************************/
/*!*********************************************!*\
!*** ./src/util/request-animation-frame.js ***!
\*********************************************/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More