Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into announce-validator
This commit is contained in:
commit
c7cdc553ff
|
@ -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.
|
||||||
|
|
|
@ -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]}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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?"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: %{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -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"},
|
||||||
|
|
6
mix.lock
6
mix.lock
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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.
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.
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
Loading…
Reference in New Issue