Browse Source

Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms

1570-levenshtein-distance-user-search
lain 4 years ago
parent
commit
814c3e5171
100 changed files with 1563 additions and 702 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +27
    -9
      config/config.exs
  3. +7
    -0
      config/description.exs
  4. +1
    -0
      docs/API/differences_in_mastoapi_responses.md
  5. +2
    -2
      docs/API/pleroma_api.md
  6. +34
    -18
      docs/configuration/cheatsheet.md
  7. +40
    -0
      installation/nginx-cache-purge.sh.example
  8. +361
    -327
      lib/pleroma/emoji/pack.ex
  9. +23
    -11
      lib/pleroma/object.ex
  10. +23
    -9
      lib/pleroma/user.ex
  11. +11
    -13
      lib/pleroma/user/query.ex
  12. +14
    -14
      lib/pleroma/web/api_spec/operations/account_operation.ex
  13. +4
    -3
      lib/pleroma/web/api_spec/operations/filter_operation.ex
  14. +7
    -1
      lib/pleroma/web/api_spec/operations/instance_operation.ex
  15. +390
    -0
      lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
  16. +79
    -0
      lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex
  17. +102
    -0
      lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
  18. +2
    -1
      lib/pleroma/web/api_spec/operations/report_operation.ex
  19. +5
    -4
      lib/pleroma/web/api_spec/operations/status_operation.ex
  20. +11
    -10
      lib/pleroma/web/api_spec/operations/subscription_operation.ex
  21. +7
    -4
      lib/pleroma/web/common_api/common_api.ex
  22. +3
    -1
      lib/pleroma/web/mastodon_api/controllers/account_controller.ex
  23. +1
    -0
      lib/pleroma/web/mastodon_api/views/instance_view.ex
  24. +0
    -21
      lib/pleroma/web/mastodon_api/views/status_view.ex
  25. +26
    -0
      lib/pleroma/web/media_proxy/invalidation.ex
  26. +40
    -0
      lib/pleroma/web/media_proxy/invalidations/http.ex
  27. +41
    -0
      lib/pleroma/web/media_proxy/invalidations/script.ex
  28. +45
    -45
      lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex
  29. +4
    -1
      lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
  30. +15
    -20
      lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
  31. +37
    -0
      lib/pleroma/web/pleroma_api/views/scrobble_view.ex
  32. +15
    -14
      lib/pleroma/web/router.ex
  33. +30
    -19
      lib/pleroma/workers/attachments_cleanup_worker.ex
  34. +1
    -1
      mix.exs
  35. +3
    -3
      mix.lock
  36. +1
    -1
      priv/static/packs/arrow-key-navigation.js
  37. +2
    -2
      priv/static/packs/base_polyfills.js
  38. +0
    -0
      priv/static/packs/base_polyfills.js.LICENSE.txt
  39. +1
    -1
      priv/static/packs/base_polyfills.js.map
  40. +2
    -2
      priv/static/packs/common.js
  41. +0
    -0
      priv/static/packs/common.js.LICENSE.txt
  42. +1
    -1
      priv/static/packs/common.js.map
  43. +2
    -2
      priv/static/packs/containers/media_container.js
  44. +86
    -86
      priv/static/packs/containers/media_container.js.LICENSE.txt
  45. +1
    -1
      priv/static/packs/containers/media_container.js.map
  46. +1
    -1
      priv/static/packs/core/admin.js
  47. +1
    -1
      priv/static/packs/core/admin.js.map
  48. +2
    -2
      priv/static/packs/core/auth.js
  49. +0
    -0
      priv/static/packs/core/auth.js.LICENSE.txt
  50. +1
    -1
      priv/static/packs/core/auth.js.map
  51. +1
    -1
      priv/static/packs/core/common.js
  52. +1
    -1
      priv/static/packs/core/common.js.map
  53. +1
    -1
      priv/static/packs/core/embed.js
  54. +1
    -1
      priv/static/packs/core/mailer.js
  55. +1
    -1
      priv/static/packs/core/modal.js
  56. +1
    -1
      priv/static/packs/core/modal.js.map
  57. +1
    -1
      priv/static/packs/core/public.js
  58. +1
    -1
      priv/static/packs/core/public.js.map
  59. +2
    -2
      priv/static/packs/core/settings.js
  60. +0
    -0
      priv/static/packs/core/settings.js.LICENSE.txt
  61. +1
    -1
      priv/static/packs/core/settings.js.map
  62. +1
    -1
      priv/static/packs/emoji_picker.js
  63. +2
    -2
      priv/static/packs/extra_polyfills.js
  64. +0
    -0
      priv/static/packs/extra_polyfills.js.LICENSE.txt
  65. +1
    -1
      priv/static/packs/extra_polyfills.js.map
  66. +1
    -1
      priv/static/packs/features/account_gallery.js
  67. +1
    -1
      priv/static/packs/features/account_gallery.js.map
  68. +1
    -1
      priv/static/packs/features/account_timeline.js
  69. +1
    -1
      priv/static/packs/features/account_timeline.js.map
  70. +1
    -1
      priv/static/packs/features/blocks.js
  71. +1
    -1
      priv/static/packs/features/blocks.js.map
  72. +1
    -1
      priv/static/packs/features/bookmarked_statuses.js
  73. +1
    -1
      priv/static/packs/features/bookmarked_statuses.js.map
  74. +1
    -1
      priv/static/packs/features/community_timeline.js
  75. +1
    -1
      priv/static/packs/features/community_timeline.js.map
  76. +1
    -1
      priv/static/packs/features/compose.js
  77. +1
    -1
      priv/static/packs/features/compose.js.map
  78. +1
    -1
      priv/static/packs/features/direct_timeline.js
  79. +1
    -1
      priv/static/packs/features/direct_timeline.js.map
  80. +1
    -1
      priv/static/packs/features/directory.js
  81. +1
    -1
      priv/static/packs/features/directory.js.map
  82. +1
    -1
      priv/static/packs/features/domain_blocks.js
  83. +1
    -1
      priv/static/packs/features/domain_blocks.js.map
  84. +1
    -1
      priv/static/packs/features/favourited_statuses.js
  85. +1
    -1
      priv/static/packs/features/favourited_statuses.js.map
  86. +1
    -1
      priv/static/packs/features/favourites.js
  87. +1
    -1
      priv/static/packs/features/favourites.js.map
  88. +1
    -1
      priv/static/packs/features/follow_requests.js
  89. +1
    -1
      priv/static/packs/features/follow_requests.js.map
  90. +1
    -1
      priv/static/packs/features/followers.js
  91. +1
    -1
      priv/static/packs/features/followers.js.map
  92. +1
    -1
      priv/static/packs/features/following.js
  93. +1
    -1
      priv/static/packs/features/following.js.map
  94. +1
    -1
      priv/static/packs/features/generic_not_found.js
  95. +1
    -1
      priv/static/packs/features/getting_started.js
  96. +1
    -1
      priv/static/packs/features/getting_started.js.map
  97. +1
    -1
      priv/static/packs/features/glitch/async/directory.js
  98. +1
    -1
      priv/static/packs/features/glitch/async/directory.js.map
  99. +1
    -1
      priv/static/packs/features/glitch/async/list_adder.js
  100. +1
    -1
      priv/static/packs/features/glitch/async/list_adder.js.map

+ 1
- 0
CHANGELOG.md 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.

### Added
- Instance: Add `background_image` to configuration and `/api/v1/instance`
- Instance: Extend `/api/v1/instance` with Pleroma-specific information.
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` to the `features` list.


+ 27
- 9
config/config.exs View File

@@ -183,6 +183,7 @@ config :pleroma, :instance,
email: "example@example.com",
notify_email: "noreply@example.com",
description: "A Pleroma instance, an alternative fediverse server",
background_image: "/images/city.jpg",
limit: 5_000,
chat_limit: 5_000,
remote_limit: 100_000,
@@ -271,20 +272,33 @@ config :pleroma, :markup,

config :pleroma, :frontend_configurations,
pleroma_fe: %{
theme: "pleroma-dark",
logo: "/static/logo.png",
background: "/images/city.jpg",
redirectRootNoLogin: "/main/all",
redirectRootLogin: "/main/friends",
showInstanceSpecificPanel: true,
scopeOptionsEnabled: false,
formattingOptionsEnabled: false,
alwaysShowSubjectInput: true,
background: "/static/aurora_borealis.jpg",
collapseMessageWithSubject: false,
disableChat: false,
greentext: false,
hideFilteredStatuses: false,
hideMutedPosts: false,
hidePostStats: false,
hideSitename: false,
hideUserStats: false,
loginMethod: "password",
logo: "/static/logo.png",
logoMargin: ".1em",
logoMask: true,
minimalScopesMode: false,
noAttachmentLinks: false,
nsfwCensorImage: "",
postContentType: "text/plain",
redirectRootLogin: "/main/friends",
redirectRootNoLogin: "/main/all",
scopeCopy: true,
sidebarRight: false,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
subjectLineBehavior: "email",
alwaysShowSubjectInput: true
theme: "pleroma-dark",
webPushNotifications: false
},
masto_fe: %{
showInstanceSpecificPanel: true
@@ -376,6 +390,10 @@ config :pleroma, :rich_media,

config :pleroma, :media_proxy,
enabled: false,
invalidation: [
enabled: false,
provider: Pleroma.Web.MediaProxy.Invalidation.Script
],
proxy_opts: [
redirect_on_failure: false,
max_body_length: 25 * 1_048_576,


+ 7
- 0
config/description.exs View File

@@ -1117,6 +1117,7 @@ config :pleroma, :config_description, [
redirectRootLogin: "/main/friends",
redirectRootNoLogin: "/main/all",
scopeCopy: true,
sidebarRight: false,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
subjectLineBehavior: "email",
@@ -1257,6 +1258,12 @@ config :pleroma, :config_description, [
description: "Copy the scope (private/unlisted/public) in replies to posts by default"
},
%{
key: :sidebarRight,
label: "Sidebar on Right",
type: :boolean,
description: "Change alignment of sidebar and panels to the right."
},
%{
key: :showFeaturesPanel,
label: "Show instance features panel",
type: :boolean,


+ 1
- 0
docs/API/differences_in_mastoapi_responses.md 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
- `background_upload_limit`: The same for backgrounds
- `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.federation`: The federation restrictions of this instance
- `vapid_public_key`: The public key needed for push messages


+ 2
- 2
docs/API/pleroma_api.md View File

@@ -265,7 +265,7 @@ See [Admin-API](admin_api.md)
* Method `PUT`
* Authentication: required
* Params:
* `image`: Multipart image
* `file`: Multipart image
* Response: JSON. Returns a mastodon media attachment entity
when successful, otherwise returns HTTP 415 `{"error": "error_msg"}`
* Example response:
@@ -426,7 +426,7 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa
* Authentication: required
* Params:
* `file`: file needs to be uploaded with the multipart request or link to remote file.
* `shortcode`: (*optional*) shortcode for new emoji, must be uniq for all emoji. If not sended, shortcode will be taken from original filename.
* `shortcode`: (*optional*) shortcode for new emoji, must be unique for all emoji. If not sended, shortcode will be taken from original filename.
* `filename`: (*optional*) new emoji file name. If not specified will be taken from original filename.
* Response: JSON, list of files for updated pack (hashmap -> shortcode => filename) with status 200, either error status with error message.



+ 34
- 18
docs/configuration/cheatsheet.md 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.
* `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
* `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

@@ -619,24 +653,6 @@ config :pleroma, :workers,
* `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]`
* 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 Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it.


+ 40
- 0
installation/nginx-cache-purge.sh.example 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

+ 361
- 327
lib/pleroma/emoji/pack.ex View File

@@ -16,162 +16,78 @@ defmodule Pleroma.Emoji.Pack do

alias Pleroma.Emoji

@spec emoji_path() :: Path.t()
def emoji_path do
static = Pleroma.Config.get!([:instance, :static_dir])
Path.join(static, "emoji")
end

@spec create(String.t()) :: :ok | {:error, File.posix()} | {:error, :empty_values}
def create(name) when byte_size(name) > 0 do
dir = Path.join(emoji_path(), name)

with :ok <- File.mkdir(dir) do
%__MODULE__{
pack_file: Path.join(dir, "pack.json")
}
def create(name) do
with :ok <- validate_not_empty([name]),
dir <- Path.join(emoji_path(), name),
:ok <- File.mkdir(dir) do
%__MODULE__{pack_file: Path.join(dir, "pack.json")}
|> save_pack()
end
end

def create(_), do: {:error, :empty_values}

@spec show(String.t()) :: {:ok, t()} | {:loaded, nil} | {:error, :empty_values}
def show(name) when byte_size(name) > 0 do
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)},
{_, pack} <- validate_pack(pack) do
{:ok, pack}
@spec show(String.t()) :: {:ok, t()} | {:error, atom()}
def show(name) do
with :ok <- validate_not_empty([name]),
{:ok, pack} <- load_pack(name) do
{:ok, validate_pack(pack)}
end
end

def show(_), do: {:error, :empty_values}

@spec delete(String.t()) ::
{:ok, [binary()]} | {:error, File.posix(), binary()} | {:error, :empty_values}
def delete(name) when byte_size(name) > 0 do
emoji_path()
|> Path.join(name)
|> File.rm_rf()
end

def delete(_), do: {:error, :empty_values}

@spec add_file(String.t(), String.t(), Path.t(), Plug.Upload.t() | String.t()) ::
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values}
def add_file(name, shortcode, filename, file)
when byte_size(name) > 0 and byte_size(shortcode) > 0 and byte_size(filename) > 0 do
with {_, nil} <- {:exists, Emoji.get(shortcode)},
{_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)} do
file_path = Path.join(pack.path, filename)

create_subdirs(file_path)

case file do
%Plug.Upload{path: upload_path} ->
# Copy the uploaded file from the temporary directory
File.copy!(upload_path, file_path)

url when is_binary(url) ->
# Download and write the file
file_contents = Tesla.get!(url).body
File.write!(file_path, file_contents)
end

files = Map.put(pack.files, shortcode, filename)

updated_pack = %{pack | files: files}

case save_pack(updated_pack) do
:ok ->
Emoji.reload()
{:ok, updated_pack}

e ->
e
end
def delete(name) do
with :ok <- validate_not_empty([name]) do
emoji_path()
|> Path.join(name)
|> File.rm_rf()
end
end

def add_file(_, _, _, _), do: {:error, :empty_values}

defp create_subdirs(file_path) do
if String.contains?(file_path, "/") do
file_path
|> Path.dirname()
|> File.mkdir_p!()
@spec add_file(String.t(), String.t(), Path.t(), Plug.Upload.t() | String.t()) ::
{:ok, t()} | {:error, File.posix() | atom()}
def add_file(name, shortcode, filename, file) do
with :ok <- validate_not_empty([name, shortcode, filename]),
:ok <- validate_emoji_not_exists(shortcode),
{:ok, pack} <- load_pack(name),
:ok <- save_file(file, pack, filename),
{:ok, updated_pack} <- pack |> put_emoji(shortcode, filename) |> save_pack() do
Emoji.reload()
{:ok, updated_pack}
end
end

@spec delete_file(String.t(), String.t()) ::
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values}
def delete_file(name, shortcode) when byte_size(name) > 0 and byte_size(shortcode) > 0 do
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)},
{_, {filename, files}} when not is_nil(filename) <-
{:exists, Map.pop(pack.files, shortcode)},
emoji <- Path.join(pack.path, filename),
{_, true} <- {:exists, File.exists?(emoji)} do
emoji_dir = Path.dirname(emoji)

File.rm!(emoji)

if String.contains?(filename, "/") and File.ls!(emoji_dir) == [] do
File.rmdir!(emoji_dir)
end

updated_pack = %{pack | files: files}

case save_pack(updated_pack) do
:ok ->
Emoji.reload()
{:ok, updated_pack}

e ->
e
end
{:ok, t()} | {:error, File.posix() | atom()}
def delete_file(name, shortcode) do
with :ok <- validate_not_empty([name, shortcode]),
{:ok, pack} <- load_pack(name),
:ok <- remove_file(pack, shortcode),
{:ok, updated_pack} <- pack |> delete_emoji(shortcode) |> save_pack() do
Emoji.reload()
{:ok, updated_pack}
end
end

def delete_file(_, _), do: {:error, :empty_values}

@spec update_file(String.t(), String.t(), String.t(), String.t(), boolean()) ::
{:ok, t()} | {:error, File.posix()} | {:error, :empty_values}
def update_file(name, shortcode, new_shortcode, new_filename, force)
when byte_size(name) > 0 and byte_size(shortcode) > 0 and byte_size(new_shortcode) > 0 and
byte_size(new_filename) > 0 do
with {_, %__MODULE__{} = pack} <- {:loaded, load_pack(name)},
{_, {filename, files}} when not is_nil(filename) <-
{:exists, Map.pop(pack.files, shortcode)},
{_, true} <- {:not_used, force or is_nil(Emoji.get(new_shortcode))} do
old_path = Path.join(pack.path, filename)
old_dir = Path.dirname(old_path)
new_path = Path.join(pack.path, new_filename)

create_subdirs(new_path)

:ok = File.rename(old_path, new_path)

if String.contains?(filename, "/") and File.ls!(old_dir) == [] do
File.rmdir!(old_dir)
end

files = Map.put(files, new_shortcode, new_filename)

updated_pack = %{pack | files: files}

case save_pack(updated_pack) do
:ok ->
Emoji.reload()
{:ok, updated_pack}

e ->
e
end
{:ok, t()} | {:error, File.posix() | atom()}
def update_file(name, shortcode, new_shortcode, new_filename, force) do
with :ok <- validate_not_empty([name, shortcode, new_shortcode, new_filename]),
{:ok, pack} <- load_pack(name),
{:ok, filename} <- get_filename(pack, shortcode),
:ok <- validate_emoji_not_exists(new_shortcode, force),
:ok <- rename_file(pack, filename, new_filename),
{:ok, updated_pack} <-
pack
|> delete_emoji(shortcode)
|> put_emoji(new_shortcode, new_filename)
|> save_pack() do
Emoji.reload()
{:ok, updated_pack}
end
end

def update_file(_, _, _, _, _), do: {:error, :empty_values}

@spec import_from_filesystem() :: {:ok, [String.t()]} | {:error, atom()}
@spec import_from_filesystem() :: {:ok, [String.t()]} | {:error, File.posix() | atom()}
def import_from_filesystem do
emoji_path = emoji_path()

@@ -184,7 +100,7 @@ defmodule Pleroma.Emoji.Pack do
File.dir?(path) and File.exists?(Path.join(path, "pack.json"))
end)
|> Enum.map(&write_pack_contents/1)
|> Enum.filter(& &1)
|> Enum.reject(&is_nil/1)

{:ok, names}
else
@@ -193,6 +109,117 @@ defmodule Pleroma.Emoji.Pack do
end
end

@spec list_remote(String.t()) :: {:ok, map()} | {:error, atom()}
def list_remote(url) do
uri = url |> String.trim() |> URI.parse()

with :ok <- validate_shareable_packs_available(uri) do
uri
|> URI.merge("/api/pleroma/emoji/packs")
|> http_get()
end
end

@spec list_local() :: {:ok, map()}
def list_local do
with {:ok, results} <- list_packs_dir() do
packs =
results
|> Enum.map(fn name ->
case load_pack(name) do
{:ok, pack} -> pack
_ -> nil
end
end)
|> Enum.reject(&is_nil/1)
|> Map.new(fn pack -> {pack.name, validate_pack(pack)} end)

{:ok, packs}
end
end

@spec get_archive(String.t()) :: {:ok, binary()} | {:error, atom()}
def get_archive(name) do
with {:ok, pack} <- load_pack(name),
:ok <- validate_downloadable(pack) do
{:ok, fetch_archive(pack)}
end
end

@spec download(String.t(), String.t(), String.t()) :: :ok | {:error, atom()}
def download(name, url, as) do
uri = url |> String.trim() |> URI.parse()

with :ok <- validate_shareable_packs_available(uri),
{:ok, remote_pack} <- uri |> URI.merge("/api/pleroma/emoji/packs/#{name}") |> http_get(),
{:ok, %{sha: sha, url: url} = pack_info} <- fetch_pack_info(remote_pack, uri, name),
{:ok, archive} <- download_archive(url, sha),
pack <- copy_as(remote_pack, as || name),
{:ok, _} = unzip(archive, pack_info, remote_pack, pack) do
# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256
# in it to depend on itself
if pack_info[:fallback] do
save_pack(pack)
else
{:ok, pack}
end
end
end

@spec save_metadata(map(), t()) :: {:ok, t()} | {:error, File.posix()}
def save_metadata(metadata, %__MODULE__{} = pack) do
pack
|> Map.put(:pack, metadata)
|> save_pack()
end

@spec update_metadata(String.t(), map()) :: {:ok, t()} | {:error, File.posix()}
def update_metadata(name, data) do
with {:ok, pack} <- load_pack(name) do
if fallback_sha_changed?(pack, data) do
update_sha_and_save_metadata(pack, data)
else
save_metadata(data, pack)
end
end
end

@spec load_pack(String.t()) :: {:ok, t()} | {:error, :not_found}
def load_pack(name) do
pack_file = Path.join([emoji_path(), name, "pack.json"])

if File.exists?(pack_file) do
pack =
pack_file
|> File.read!()
|> from_json()
|> Map.put(:pack_file, pack_file)
|> Map.put(:path, Path.dirname(pack_file))
|> Map.put(:name, name)

{:ok, pack}
else
{:error, :not_found}
end
end

@spec emoji_path() :: Path.t()
defp emoji_path do
[:instance, :static_dir]
|> Pleroma.Config.get!()
|> Path.join("emoji")
end

defp validate_emoji_not_exists(shortcode, force \\ false)
defp validate_emoji_not_exists(_shortcode, true), do: :ok

defp validate_emoji_not_exists(shortcode, _) do
case Emoji.get(shortcode) do
nil -> :ok
_ -> {:error, :already_exists}
end
end

defp write_pack_contents(path) do
pack = %__MODULE__{
files: files_from_path(path),
@@ -201,7 +228,7 @@ defmodule Pleroma.Emoji.Pack do
}

case save_pack(pack) do
:ok -> Path.basename(path)
{:ok, _pack} -> Path.basename(path)
_ -> nil
end
end
@@ -216,7 +243,8 @@ defmodule Pleroma.Emoji.Pack do
# FIXME: Copy-pasted from Pleroma.Emoji/load_from_file_stream/2

# Create a map of shortcodes to filenames from emoji.txt
File.read!(txt_path)
txt_path
|> File.read!()
|> String.split("\n")
|> Enum.map(&String.trim/1)
|> Enum.map(fn line ->
@@ -226,21 +254,18 @@ defmodule Pleroma.Emoji.Pack do
[name, file | _] ->
file_dir_name = Path.dirname(file)

file =
if String.ends_with?(path, file_dir_name) do
Path.basename(file)
else
file
end

{name, file}
if String.ends_with?(path, file_dir_name) do
{name, Path.basename(file)}
else
{name, file}
end

_ ->
nil
end
end)
|> Enum.filter(& &1)
|> Enum.into(%{})
|> Enum.reject(&is_nil/1)
|> Map.new()
else
# If there's no emoji.txt, assume all files
# that are of certain extensions from the config are emojis and import them all
@@ -249,60 +274,20 @@ defmodule Pleroma.Emoji.Pack do
end
end

@spec list_remote(String.t()) :: {:ok, map()}
def list_remote(url) do
uri =
url
|> String.trim()
|> URI.parse()

with {_, true} <- {:shareable, shareable_packs_available?(uri)} do
packs =
uri
|> URI.merge("/api/pleroma/emoji/packs")
|> to_string()
|> Tesla.get!()
|> Map.get(:body)
|> Jason.decode!()

{:ok, packs}
end
end

@spec list_local() :: {:ok, map()}
def list_local do
emoji_path = emoji_path()

# Create the directory first if it does not exist. This is probably the first request made
# with the API so it should be sufficient
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_path)},
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do
packs =
results
|> Enum.map(&load_pack/1)
|> Enum.filter(& &1)
|> Enum.map(&validate_pack/1)
|> Map.new()

{:ok, packs}
end
end

defp validate_pack(pack) do
if downloadable?(pack) do
archive = fetch_archive(pack)
archive_sha = :crypto.hash(:sha256, archive) |> Base.encode16()
info =
if downloadable?(pack) do
archive = fetch_archive(pack)
archive_sha = :crypto.hash(:sha256, archive) |> Base.encode16()

info =
pack.pack
|> Map.put("can-download", true)
|> Map.put("download-sha256", archive_sha)
else
Map.put(pack.pack, "can-download", false)
end

{pack.name, Map.put(pack, :pack, info)}
else
info = Map.put(pack.pack, "can-download", false)
{pack.name, Map.put(pack, :pack, info)}
end
Map.put(pack, :pack, info)
end

defp downloadable?(pack) do
@@ -315,26 +300,6 @@ defmodule Pleroma.Emoji.Pack do
end)
end

@spec get_archive(String.t()) :: {:ok, binary()}
def get_archive(name) do
with {_, %__MODULE__{} = pack} <- {:exists?, load_pack(name)},
{_, true} <- {:can_download?, downloadable?(pack)} do
{:ok, fetch_archive(pack)}
end
end

defp fetch_archive(pack) do
hash = :crypto.hash(:md5, File.read!(pack.pack_file))

case Cachex.get!(:emoji_packs_cache, pack.name) do
%{hash: ^hash, pack_data: archive} ->
archive

_ ->
create_archive_and_cache(pack, hash)
end
end

defp create_archive_and_cache(pack, hash) do
files = ['pack.json' | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)]

@@ -356,152 +321,221 @@ defmodule Pleroma.Emoji.Pack do
result
end

@spec download(String.t(), String.t(), String.t()) :: :ok
def download(name, url, as) do
uri =
url
|> String.trim()
|> URI.parse()

with {_, true} <- {:shareable, shareable_packs_available?(uri)} do
remote_pack =
uri
|> URI.merge("/api/pleroma/emoji/packs/#{name}")
|> to_string()
|> Tesla.get!()
|> Map.get(:body)
|> Jason.decode!()

result =
case remote_pack["pack"] do
%{"share-files" => true, "can-download" => true, "download-sha256" => sha} ->
{:ok,
%{
sha: sha,
url: URI.merge(uri, "/api/pleroma/emoji/packs/#{name}/archive") |> to_string()
}}

%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) ->
{:ok,
%{
sha: sha,
url: src,
fallback: true
}}
defp save_pack(pack) do
with {:ok, json} <- Jason.encode(pack, pretty: true),
:ok <- File.write(pack.pack_file, json) do
{:ok, pack}
end
end

_ ->
{:error,
"The pack was not set as shared and there is no fallback src to download from"}
end
defp from_json(json) do
map = Jason.decode!(json)

with {:ok, %{sha: sha, url: url} = pinfo} <- result,
%{body: archive} <- Tesla.get!(url),
{_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, archive)} do
local_name = as || name
struct(__MODULE__, %{files: map["files"], pack: map["pack"]})
end

path = Path.join(emoji_path(), local_name)
defp validate_shareable_packs_available(uri) do
with {:ok, %{"links" => links}} <- uri |> URI.merge("/.well-known/nodeinfo") |> http_get(),
# Get the actual nodeinfo address and fetch it
{:ok, %{"metadata" => %{"features" => features}}} <-
links |> List.last() |> Map.get("href") |> http_get() do
if Enum.member?(features, "shareable_emoji_packs") do
:ok
else
{:error, :not_shareable}
end
end
end

pack = %__MODULE__{
name: local_name,
path: path,
files: remote_pack["files"],
pack_file: Path.join(path, "pack.json")
}
defp validate_not_empty(list) do
if Enum.all?(list, fn i -> is_binary(i) and i != "" end) do
:ok
else
{:error, :empty_values}
end
end

File.mkdir_p!(pack.path)
defp save_file(file, pack, filename) do
file_path = Path.join(pack.path, filename)
create_subdirs(file_path)

files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
files = if pinfo[:fallback], do: files, else: ['pack.json' | files]
case file do
%Plug.Upload{path: upload_path} ->
# Copy the uploaded file from the temporary directory
with {:ok, _} <- File.copy(upload_path, file_path), do: :ok

{:ok, _} = :zip.unzip(archive, cwd: to_charlist(pack.path), file_list: files)
url when is_binary(url) ->
# Download and write the file
file_contents = Tesla.get!(url).body
File.write(file_path, file_contents)
end
end

# Fallback can't contain a pack.json file, since that would cause the fallback-src-sha256
# in it to depend on itself
if pinfo[:fallback] do
save_pack(pack)
end
defp put_emoji(pack, shortcode, filename) do
files = Map.put(pack.files, shortcode, filename)
%{pack | files: files}
end

:ok
end
defp delete_emoji(pack, shortcode) do
files = Map.delete(pack.files, shortcode)
%{pack | files: files}
end

defp rename_file(pack, filename, new_filename) do
old_path = Path.join(pack.path, filename)
new_path = Path.join(pack.path, new_filename)
create_subdirs(new_path)

with :ok <- File.rename(old_path, new_path) do
remove_dir_if_empty(old_path, filename)
end
end

defp save_pack(pack), do: File.write(pack.pack_file, Jason.encode!(pack, pretty: true))
defp create_subdirs(file_path) do
if String.contains?(file_path, "/") do
file_path
|> Path.dirname()
|> File.mkdir_p!()
end
end

@spec save_metadata(map(), t()) :: {:ok, t()} | {:error, File.posix()}
def save_metadata(metadata, %__MODULE__{} = pack) do
pack = Map.put(pack, :pack, metadata)
defp remove_file(pack, shortcode) do
with {:ok, filename} <- get_filename(pack, shortcode),
emoji <- Path.join(pack.path, filename),
:ok <- File.rm(emoji) do
remove_dir_if_empty(emoji, filename)
end
end

with :ok <- save_pack(pack) do
{:ok, pack}
defp remove_dir_if_empty(emoji, filename) do
dir = Path.dirname(emoji)

if String.contains?(filename, "/") and File.ls!(dir) == [] do
File.rmdir!(dir)
else
:ok
end
end

@spec update_metadata(String.t(), map()) :: {:ok, t()} | {:error, File.posix()}
def update_metadata(name, data) do
pack = load_pack(name)
defp get_filename(pack, shortcode) do
with %{^shortcode => filename} when is_binary(filename) <- pack.files,
true <- pack.path |> Path.join(filename) |> File.exists?() do
{:ok, filename}
else
_ -> {:error, :doesnt_exist}
end
end

fb_sha_changed? =
not is_nil(data["fallback-src"]) and data["fallback-src"] != pack.pack["fallback-src"]
defp http_get(%URI{} = url), do: url |> to_string() |> http_get()

with {_, true} <- {:update?, fb_sha_changed?},
{:ok, %{body: zip}} <- Tesla.get(data["fallback-src"]),
{:ok, f_list} <- :zip.unzip(zip, [:memory]),
{_, true} <- {:has_all_files?, has_all_files?(pack.files, f_list)} do
fallback_sha = :crypto.hash(:sha256, zip) |> Base.encode16()
defp http_get(url) do
with {:ok, %{body: body}} <- url |> Pleroma.HTTP.get() do
Jason.decode(body)
end
end

data
|> Map.put("fallback-src-sha256", fallback_sha)
|> save_metadata(pack)
defp list_packs_dir do
emoji_path = emoji_path()
# Create the directory first if it does not exist. This is probably the first request made
# with the API so it should be sufficient
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_path)},
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_path)} do
{:ok, results}
else
{:update?, _} -> save_metadata(data, pack)
e -> e
{:create_dir, {:error, e}} -> {:error, :create_dir, e}
{:ls, {:error, e}} -> {:error, :ls, e}
end
end

# Check if all files from the pack.json are in the archive
defp has_all_files?(files, f_list) do
Enum.all?(files, fn {_, from_manifest} ->
List.keyfind(f_list, to_charlist(from_manifest), 0)
end)
defp validate_downloadable(pack) do
if downloadable?(pack), do: :ok, else: {:error, :cant_download}
end

@spec load_pack(String.t()) :: t() | nil
def load_pack(name) do
pack_file = Path.join([emoji_path(), name, "pack.json"])
defp copy_as(remote_pack, local_name) do
path = Path.join(emoji_path(), local_name)

if File.exists?(pack_file) do
pack_file
|> File.read!()
|> from_json()
|> Map.put(:pack_file, pack_file)
|> Map.put(:path, Path.dirname(pack_file))
|> Map.put(:name, name)
%__MODULE__{
name: local_name,
path: path,
files: remote_pack["files"],
pack_file: Path.join(path, "pack.json")
}
end

defp unzip(archive, pack_info, remote_pack, local_pack) do
with :ok <- File.mkdir_p!(local_pack.path) do
files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
files = if pack_info[:fallback], do: files, else: ['pack.json' | files]

:zip.unzip(archive, cwd: to_charlist(local_pack.path), file_list: files)
end
end

defp from_json(json) do
map = Jason.decode!(json)
defp fetch_pack_info(remote_pack, uri, name) do
case remote_pack["pack"] do
%{"share-files" => true, "can-download" => true, "download-sha256" => sha} ->
{:ok,
%{
sha: sha,
url: URI.merge(uri, "/api/pleroma/emoji/packs/#{name}/archive") |> to_string()
}}

%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) ->
{:ok,
%{
sha: sha,
url: src,
fallback: true
}}

struct(__MODULE__, %{files: map["files"], pack: map["pack"]})
_ ->
{:error, "The pack was not set as shared and there is no fallback src to download from"}
end
end

defp download_archive(url, sha) do
with {:ok, %{body: archive}} <- Tesla.get(url) do
if Base.decode16!(sha) == :crypto.hash(:sha256, archive) do
{:ok, archive}
else
{:error, :imvalid_checksum}
end
end
end

defp fetch_archive(pack) do
hash = :crypto.hash(:md5, File.read!(pack.pack_file))

case Cachex.get!(:emoji_packs_cache, pack.name) do
%{hash: ^hash, pack_data: archive} -> archive
_ -> create_archive_and_cache(pack, hash)
end
end

defp fallback_sha_changed?(pack, data) do
is_binary(data[:"fallback-src"]) and data[:"fallback-src"] != pack.pack["fallback-src"]
end

defp update_sha_and_save_metadata(pack, data) do
with {:ok, %{body: zip}} <- Tesla.get(data[:"fallback-src"]),
:ok <- validate_has_all_files(pack, zip) do
fallback_sha = :sha256 |> :crypto.hash(zip) |> Base.encode16()

data
|> Map.put("fallback-src-sha256", fallback_sha)
|> save_metadata(pack)
end
end

defp shareable_packs_available?(uri) do
uri
|> URI.merge("/.well-known/nodeinfo")
|> to_string()
|> Tesla.get!()
|> Map.get(:body)
|> Jason.decode!()
|> Map.get("links")
|> List.last()
|> Map.get("href")
# Get the actual nodeinfo address and fetch it
|> Tesla.get!()
|> Map.get(:body)
|> Jason.decode!()
|> get_in(["metadata", "features"])
|> Enum.member?("shareable_emoji_packs")
defp validate_has_all_files(pack, zip) do
with {:ok, f_list} <- :zip.unzip(zip, [:memory]) do
# Check if all files from the pack.json are in the archive
pack.files
|> Enum.all?(fn {_, from_manifest} ->
List.keyfind(f_list, to_charlist(from_manifest), 0)
end)
|> if(do: :ok, else: {:error, :incomplete})
end
end
end

+ 23
- 11
lib/pleroma/object.ex View File

@@ -9,11 +9,13 @@ defmodule Pleroma.Object do
import Ecto.Changeset

alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.ObjectTombstone
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Workers.AttachmentsCleanupWorker

require Logger

@@ -188,27 +190,37 @@ defmodule Pleroma.Object do
def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object),
deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
with true <- Pleroma.Config.get([:instance, :cleanup_attachments]) do
{:ok, _} =
Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{
"object" => object
})
end
{:ok, _} <- invalid_object_cache(object) do
cleanup_attachments(
Config.get([:instance, :cleanup_attachments]),
%{"object" => object}
)

{:ok, object, deleted_activity}
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),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
{:ok, _} <- invalid_object_cache(object) do
{:ok, object}
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
Cachex.put(:object_cache, "object:#{ap_id}", object)
{:ok, object}


+ 23
- 9
lib/pleroma/user.ex View File

@@ -1204,7 +1204,9 @@ defmodule Pleroma.User do
def get_recipients_from_activity(%Activity{recipients: to, actor: actor}) do
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()
end

@@ -1430,6 +1432,25 @@ defmodule Pleroma.User do
BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
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)

@spec perform(atom(), User.t()) :: {:ok, User.t()}
@@ -1451,14 +1472,7 @@ defmodule Pleroma.User do

delete_user_activities(user)

if user.local do
user
|> change(%{deactivated: true, email: nil})
|> update_and_set_cache()
else
invalidate_cache(user)
Repo.delete(user)
end
delete_or_deactivate(user)
end

def perform(:deactivate_async, user, status), do: deactivate(user, status)


+ 11
- 13
lib/pleroma/user/query.ex View File

@@ -167,20 +167,18 @@ defmodule Pleroma.User.Query do
end

defp compose_query({:recipients_from_activity, to}, query) do
query
|> join(:left, [u], r in FollowingRelationship,
as: :relationships,
on: r.follower_id == u.id
)
|> join(:left, [relationships: r], f in User,
as: :following,
on: f.id == r.following_id
)
|> where(
[u, following: f, relationships: r],
u.ap_id in ^to or (f.follower_address in ^to and r.state == ^:follow_accept)
following_query =
from(u in User,
join: f in FollowingRelationship,
on: u.id == f.following_id,
where: f.state == ^:follow_accept,
where: u.follower_address in ^to,
select: f.follower_id
)

from(u in query,
where: u.ap_id in ^to or u.id in subquery(following_query)
)
|> distinct(true)
end

defp compose_query({:order_by, key}, query) do


+ 14
- 14
lib/pleroma/web/api_spec/operations/account_operation.ex View File

@@ -393,7 +393,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
format: :password
},
agreement: %Schema{
type: :boolean,
allOf: [BooleanLike],
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."
},
@@ -463,7 +463,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
type: :object,
properties: %{
bot: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Whether the account has a bot flag."
},
@@ -486,7 +486,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
format: :binary
},
locked: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Whether manual approval of follow requests is required."
},
@@ -510,37 +510,37 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do

# Pleroma-specific fields
no_rich_text: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "html tags are stripped from all statuses requested from the API"
},
hide_followers: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's followers will be hidden"
},
hide_follows: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's follows will be hidden"
},
hide_followers_count: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's follower count will be hidden"
},
hide_follows_count: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's follow count will be hidden"
},
hide_favorites: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's favorites timeline will be hidden"
},
show_role: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "user's role (e.g admin, moderator) will be exposed to anyone in the
API"
@@ -552,12 +552,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
description: "Opaque user settings to be saved on the backend."
},
skip_thread_containment: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Skip filtering out broken threads"
},
allow_following_move: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Allows automatically follow moved following accounts"
},
@@ -568,7 +568,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
format: :binary
},
discoverable: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description:
"Discovery of this account in search results and other services is allowed."
@@ -678,7 +678,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
type: :object,
properties: %{
notifications: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Mute notifications in addition to statuses? Defaults to true.",
default: true


+ 4
- 3
lib/pleroma/web/api_spec/operations/filter_operation.ex View File

@@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike

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


+ 7
- 1
lib/pleroma/web/api_spec/operations/instance_operation.ex View File

@@ -125,11 +125,17 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
},
avatar_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: %{
"avatar_upload_limit" => 2_000_000,
"background_upload_limit" => 4_000_000,
"background_image" => "/static/image.png",
"banner_upload_limit" => 4_000_000,
"description" => "A Pleroma instance, an alternative fediverse server",
"email" => "lain@lain.com",


+ 390
- 0
lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex View File

@@ -0,0 +1,390 @@
# 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.PleromaEmojiPackOperation 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 remote_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Make request to another instance for emoji packs list",
security: [%{"oAuth" => ["write"]}],
parameters: [url_param()],
operationId: "PleromaAPI.EmojiPackController.remote",
responses: %{
200 => emoji_packs_response(),
500 => Operation.response("Error", "application/json", ApiError)
}
}
end

def index_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Lists local custom emoji packs",
operationId: "PleromaAPI.EmojiPackController.index",
responses: %{
200 => emoji_packs_response()
}
}
end

def show_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Show emoji pack",
operationId: "PleromaAPI.EmojiPackController.show",
parameters: [name_param()],
responses: %{
200 => Operation.response("Emoji Pack", "application/json", emoji_pack()),
400 => Operation.response("Bad Request", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

def archive_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Requests a local pack archive from the instance",
operationId: "PleromaAPI.EmojiPackController.archive",
parameters: [name_param()],
responses: %{
200 =>
Operation.response("Archive file", "application/octet-stream", %Schema{
type: :string,
format: :binary
}),
403 => Operation.response("Forbidden", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

def download_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Download pack from another instance",
operationId: "PleromaAPI.EmojiPackController.download",
security: [%{"oAuth" => ["write"]}],
requestBody: request_body("Parameters", download_request(), required: true),
responses: %{
200 => ok_response(),
500 => Operation.response("Error", "application/json", ApiError)
}
}
end

defp download_request do
%Schema{
type: :object,
required: [:url, :name],
properties: %{
url: %Schema{
type: :string,
format: :uri,
description: "URL of the instance to download from"
},
name: %Schema{type: :string, format: :uri, description: "Pack Name"},
as: %Schema{type: :string, format: :uri, description: "Save as"}
}
}
end

def create_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Create an empty pack",
operationId: "PleromaAPI.EmojiPackController.create",
security: [%{"oAuth" => ["write"]}],
parameters: [name_param()],
responses: %{
200 => ok_response(),
400 => Operation.response("Not Found", "application/json", ApiError),
409 => Operation.response("Conflict", "application/json", ApiError),
500 => Operation.response("Error", "application/json", ApiError)
}
}
end

def delete_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Delete a custom emoji pack",
operationId: "PleromaAPI.EmojiPackController.delete",
security: [%{"oAuth" => ["write"]}],
parameters: [name_param()],
responses: %{
200 => ok_response(),
400 => Operation.response("Bad Request", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end

def update_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Updates (replaces) pack metadata",
operationId: "PleromaAPI.EmojiPackController.update",
security: [%{"oAuth" => ["write"]}],
requestBody: request_body("Parameters", update_request(), required: true),
parameters: [name_param()],
responses: %{
200 => Operation.response("Metadata", "application/json", metadata()),
400 => Operation.response("Bad Request", "application/json", ApiError)
}
}
end

def add_file_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Add new file to the pack",
operationId: "PleromaAPI.EmojiPackController.add_file",
security: [%{"oAuth" => ["write"]}],
requestBody: request_body("Parameters", add_file_request(), required: true),
parameters: [name_param()],
responses: %{
200 => Operation.response("Files Object", "application/json", files_object()),
400 => Operation.response("Bad Request", "application/json", ApiError),
409 => Operation.response("Conflict", "application/json", ApiError)
}
}
end

defp add_file_request do
%Schema{
type: :object,
required: [:file],
properties: %{
file: %Schema{
description:
"File needs to be uploaded with the multipart request or link to remote file",
anyOf: [
%Schema{type: :string, format: :binary},
%Schema{type: :string, format: :uri}
]
},
shortcode: %Schema{
type: :string,
description:
"Shortcode for new emoji, must be unique for all emoji. If not sended, shortcode will be taken from original filename."
},
filename: %Schema{
type: :string,
description:
"New emoji file name. If not specified will be taken from original filename."
}
}
}
end

def update_file_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Add new file to the pack",
operationId: "PleromaAPI.EmojiPackController.update_file",
security: [%{"oAuth" => ["write"]}],
requestBody: request_body("Parameters", update_file_request(), required: true),
parameters: [name_param()],
responses: %{
200 => Operation.response("Files Object", "application/json", files_object()),
400 => Operation.response("Bad Request", "application/json", ApiError),
409 => Operation.response("Conflict", "application/json", ApiError)
}
}
end

defp update_file_request do
%Schema{
type: :object,
required: [:shortcode, :new_shortcode, :new_filename],
properties: %{
shortcode: %Schema{
type: :string,
description: "Emoji file shortcode"
},
new_shortcode: %Schema{
type: :string,
description: "New emoji file shortcode"
},
new_filename: %Schema{
type: :string,
description: "New filename for emoji file"
},
force: %Schema{
type: :boolean,
description: "With true value to overwrite existing emoji with new shortcode",
default: false
}
}
}
end

def delete_file_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Delete emoji file from pack",
operationId: "PleromaAPI.EmojiPackController.delete_file",
security: [%{"oAuth" => ["write"]}],
parameters: [
name_param(),
Operation.parameter(:shortcode, :query, :string, "File shortcode",
example: "cofe",
required: true
)
],
responses: %{
200 => Operation.response("Files Object", "application/json", files_object()),
400 => Operation.response("Bad Request", "application/json", ApiError)
}
}
end

def import_from_filesystem_operation do
%Operation{
tags: ["Emoji Packs"],
summary: "Imports packs from filesystem",
operationId: "PleromaAPI.EmojiPackController.import",
security: [%{"oAuth" => ["write"]}],
responses: %{
200 =>
Operation.response("Array of imported pack names", "application/json", %Schema{
type: :array,
items: %Schema{type: :string}
})
}
}
end

defp name_param do
Operation.parameter(:name, :path, :string, "Pack Name", example: "cofe", required: true)
end

defp url_param do
Operation.parameter(
:url,
:query,
%Schema{type: :string, format: :uri},
"URL of the instance",
required: true
)
end

defp ok_response do
Operation.response("Ok", "application/json", %Schema{type: :string, example: "ok"})
end

defp emoji_packs_response do
Operation.response(
"Object with pack names as keys and pack contents as values",
"application/json",
%Schema{
type: :object,
additionalProperties: emoji_pack(),
example: %{
"emojos" => emoji_pack().example
}
}
)
end

defp emoji_pack do
%Schema{
title: "EmojiPack",
type: :object,
properties: %{
files: files_object(),
pack: %Schema{
type: :object,
properties: %{
license: %Schema{type: :string},
homepage: %Schema{type: :string, format: :uri},
description: %Schema{type: :string},
"can-download": %Schema{type: :boolean},
"share-files": %Schema{type: :boolean},
"download-sha256": %Schema{type: :string}
}
}
},
example: %{
"files" => %{"emacs" => "emacs.png", "guix" => "guix.png"},
"pack" => %{
"license" => "Test license",
"homepage" => "https://pleroma.social",
"description" => "Test description",
"can-download" => true,
"share-files" => true,
"download-sha256" => "57482F30674FD3DE821FF48C81C00DA4D4AF1F300209253684ABA7075E5FC238"
}
}
}
end

defp files_object do
%Schema{
type: :object,
additionalProperties: %Schema{type: :string},
description: "Object with emoji names as keys and filenames as values"
}
end

defp update_request do
%Schema{
type: :object,
properties: %{
metadata: %Schema{
type: :object,
description: "Metadata to replace the old one",
properties: %{
license: %Schema{type: :string},
homepage: %Schema{type: :string, format: :uri},
description: %Schema{type: :string},
"fallback-src": %Schema{
type: :string,
format: :uri,
description: "Fallback url to download pack from"
},
"fallback-src-sha256": %Schema{
type: :string,
description: "SHA256 encoded for fallback pack archive"
},
"share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"}
}
}
}
}
end

defp metadata do
%Schema{
type: :object,
properties: %{
license: %Schema{type: :string},
homepage: %Schema{type: :string, format: :uri},
description: %Schema{type: :string},
"fallback-src": %Schema{
type: :string,
format: :uri,
description: "Fallback url to download pack from"
},
"fallback-src-sha256": %Schema{
type: :string,
description: "SHA256 encoded for fallback pack archive"
},
"share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"}
}
}
end
end

+ 79
- 0
lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex 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

+ 102
- 0
lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex 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

+ 2
- 1
lib/pleroma/web/api_spec/operations/report_operation.ex View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike

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


+ 5
- 4
lib/pleroma/web/api_spec/operations/status_operation.ex View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.AccountOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
alias Pleroma.Web.ApiSpec.Schemas.Status
@@ -394,12 +395,12 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
},
multiple: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Allow multiple choices?"
},
hide_totals: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Hide vote counts until the poll ends?"
}
@@ -411,7 +412,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
description: "ID of the status being replied to, if status is a reply"
},
sensitive: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
description: "Mark status and attached media as sensitive?"
},
@@ -435,7 +436,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
},
# Pleroma-specific properties:
preview: %Schema{
type: :boolean,
allOf: [BooleanLike],
nullable: true,
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"


+ 11
- 10
lib/pleroma/web/api_spec/operations/subscription_operation.ex View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.PushSubscription

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


+ 7
- 4
lib/pleroma/web/common_api/common_api.ex View File

@@ -387,11 +387,14 @@ defmodule Pleroma.Web.CommonAPI do
|> check_expiry_date()
end

def listen(user, %{"title" => _} = data) do
with visibility <- data["visibility"] || "public",
{to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
def listen(user, data) do
visibility = Map.get(data, :visibility, "public")

with {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
listen_data <-
Map.take(data, ["album", "artist", "title", "length"])
data
|> Map.take([:album, :artist, :title, :length])
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Audio")
|> Map.put("to", to)
|> Map.put("cc", cc)


+ 3
- 1
lib/pleroma/web/mastodon_api/controllers/account_controller.ex View File

@@ -177,6 +177,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
)
|> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store)
|> add_if_present(params, :default_scope, :default_scope)
|> add_if_present(params["source"], "privacy", :default_scope)
|> add_if_present(params, :actor_type, :actor_type)

changeset = User.update_changeset(user, user_params)
@@ -189,7 +190,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end

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
Map.put(map, map_field, new_value)
else


+ 1
- 0
lib/pleroma/web/mastodon_api/views/instance_view.ex View File

@@ -33,6 +33,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),
background_upload_limit: Keyword.get(instance, :background_upload_limit),
banner_upload_limit: Keyword.get(instance, :banner_upload_limit),
background_image: Keyword.get(instance, :background_image),
pleroma: %{
metadata: %{
features: features(),


+ 0
- 21
lib/pleroma/web/mastodon_api/views/status_view.ex View File

@@ -436,27 +436,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
}
end

def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
object = Object.normalize(activity)

user = get_user(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"])

%{
id: activity.id,
account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
created_at: created_at,
title: object.data["title"] |> HTML.strip_tags(),
artist: object.data["artist"] |> HTML.strip_tags(),
album: object.data["album"] |> HTML.strip_tags(),
length: object.data["length"]
}
end

def render("listens.json", opts) do
safe_render_many(opts.activities, StatusView, "listen.json", opts)
end

def render("context.json", %{activity: activity, activities: activities, user: user}) do
%{ancestors: ancestors, descendants: descendants} =
activities


+ 26
- 0
lib/pleroma/web/media_proxy/invalidation.ex 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

+ 40
- 0
lib/pleroma/web/media_proxy/invalidations/http.ex 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

+ 41
- 0
lib/pleroma/web/media_proxy/invalidations/script.ex 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

lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex → lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex View File

@@ -1,8 +1,10 @@
defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
use Pleroma.Web, :controller

alias Pleroma.Emoji.Pack

plug(Pleroma.Web.ApiSpec.CastAndValidate)

plug(
Pleroma.Plugs.OAuthScopesPlug,
%{scopes: ["write"], admin: true}
@@ -19,39 +21,37 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
]
)

plug(
:skip_plug,
[Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
when action in [:archive, :show, :list]
)
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list])

defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation

def remote(conn, %{"url" => url}) do
def remote(conn, %{url: url}) do
with {:ok, packs} <- Pack.list_remote(url) do
json(conn, packs)
else
{:shareable, _} ->
{:error, :not_shareable} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "The requested instance does not support sharing emoji packs"})
end
end

def list(conn, _params) do
def index(conn, _params) do
emoji_path =
Path.join(
Pleroma.Config.get!([:instance, :static_dir]),
"emoji"
)
[:instance, :static_dir]
|> Pleroma.Config.get!()
|> Path.join("emoji")

with {:ok, packs} <- Pack.list_local() do
json(conn, packs)
else
{:create_dir, {:error, e}} ->
{:error, :create_dir, e} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"})

{:ls, {:error, e}} ->
{:error, :ls, e} ->
conn
|> put_status(:internal_server_error)
|> json(%{
@@ -60,13 +60,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def show(conn, %{"name" => name}) do
def show(conn, %{name: name}) do
name = String.trim(name)

with {:ok, pack} <- Pack.show(name) do
json(conn, pack)
else
{:loaded, _} ->
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Pack #{name} does not exist"})
@@ -78,11 +78,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def archive(conn, %{"name" => name}) do
def archive(conn, %{name: name}) do
with {:ok, archive} <- Pack.get_archive(name) do
send_download(conn, {:binary, archive}, filename: "#{name}.zip")
else
{:can_download?, _} ->
{:error, :cant_download} ->
conn
|> put_status(:forbidden)
|> json(%{
@@ -90,23 +90,23 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
"Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
})

{:exists?, _} ->
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Pack #{name} does not exist"})
end
end

def download(conn, %{"url" => url, "name" => name} = params) do
with :ok <- Pack.download(name, url, params["as"]) do
def download(%{body_params: %{url: url, name: name} = params} = conn, _) do
with {:ok, _pack} <- Pack.download(name, url, params[:as]) do
json(conn, "ok")
else
{:shareable, _} ->
{:error, :not_shareable} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "The requested instance does not support sharing emoji packs"})

{:checksum, _} ->
{:error, :imvalid_checksum} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"})
@@ -118,10 +118,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def create(conn, %{"name" => name}) do
def create(conn, %{name: name}) do
name = String.trim(name)

with :ok <- Pack.create(name) do
with {:ok, _pack} <- Pack.create(name) do
json(conn, "ok")
else
{:error, :eexist} ->
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def delete(conn, %{"name" => name}) do
def delete(conn, %{name: name}) do
name = String.trim(name)

with {:ok, deleted} when deleted != [] <- Pack.delete(name) do
@@ -166,11 +166,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def update(conn, %{"name" => name, "metadata" => metadata}) do
def update(%{body_params: %{metadata: metadata}} = conn, %{name: name}) do
with {:ok, pack} <- Pack.update_metadata(name, metadata) do
json(conn, pack.pack)
else
{:has_all_files?, _} ->
{:error, :incomplete} ->
conn
|> put_status(:bad_request)
|> json(%{error: "The fallback archive does not have all files specified in pack.json"})
@@ -184,19 +184,19 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def add_file(conn, %{"name" => name} = params) do
filename = params["filename"] || get_filename(params["file"])
shortcode = params["shortcode"] || Path.basename(filename, Path.extname(filename))
def add_file(%{body_params: params} = conn, %{name: name}) do
filename = params[:filename] || get_filename(params[:file])
shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename))

with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params["file"]) do
with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params[:file]) do
json(conn, pack.files)
else
{:exists, _} ->
{:error, :already_exists} ->
conn
|> put_status(:conflict)
|> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"})

{:loaded, _} ->
{:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})
@@ -215,20 +215,20 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def update_file(conn, %{"name" => name, "shortcode" => shortcode} = params) do
new_shortcode = params["new_shortcode"]
new_filename = params["new_filename"]
force = params["force"] == true
def update_file(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: name}) do
new_shortcode = params[:new_shortcode]
new_filename = params[:new_filename]
force = params[:force]

with {:ok, pack} <- Pack.update_file(name, shortcode, new_shortcode, new_filename, force) do
json(conn, pack.files)
else
{:exists, _} ->
{:error, :doesnt_exist} ->
conn
|> put_status(:bad_request)
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"})

{:not_used, _} ->
{:error, :already_exists} ->
conn
|> put_status(:conflict)
|> json(%{
@@ -236,7 +236,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
"New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option"
})

{:loaded, _} ->
{:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})
@@ -255,16 +255,16 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end

def delete_file(conn, %{"name" => name, "shortcode" => shortcode}) do
def delete_file(conn, %{name: name, shortcode: shortcode}) do
with {:ok, pack} <- Pack.delete_file(name, shortcode) do
json(conn, pack.files)
else
{:exists, _} ->
{:error, :doesnt_exist} ->
conn
|> put_status(:bad_request)
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"})

{:loaded, _} ->
{:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})

+ 4
- 1
lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex View File

@@ -9,16 +9,19 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub

plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read: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"
def show(%{assigns: %{user: user}} = conn, _params) do
json(conn, User.get_mascot(user))
end

@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)),
# Reject if not an image
%{type: "image"} = attachment <- render_attachment(object) do


+ 15
- 20
lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex View File

@@ -5,34 +5,27 @@
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
use Pleroma.Web, :controller

import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2]
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]

alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.StatusView

plug(Pleroma.Web.ApiSpec.CastAndValidate)

plug(
OAuthScopesPlug,
%{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :user_scrobbles
%{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :index
)

plug(OAuthScopesPlug, %{scopes: ["write"]} when action != :user_scrobbles)
plug(OAuthScopesPlug, %{scopes: ["write"]} when action == :create)

def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do
params =
if !params["length"] do
params
else
params
|> Map.put("length", fetch_integer_param(params, "length"))
end
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaScrobbleOperation

def create(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, activity} <- CommonAPI.listen(user, params) do
conn
|> put_view(StatusView)
|> render("listen.json", %{activity: activity, for: user})
render(conn, "show.json", activity: activity, for: user)
else
{:error, message} ->
conn
@@ -41,16 +34,18 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
end
end

def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do
with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
params = Map.put(params, "type", ["Listen"])
def index(%{assigns: %{user: reading_user}} = conn, %{id: id} = params) do
with %User{} = user <- User.get_cached_by_nickname_or_id(id, for: reading_user) do
params =
params
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", ["Listen"])

activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params)

conn
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("listens.json", %{
|> render("index.json", %{
activities: activities,
for: reading_user,
as: :activity


+ 37
- 0
lib/pleroma/web/pleroma_api/views/scrobble_view.ex 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

+ 15
- 14
lib/pleroma/web/router.ex View File

@@ -216,24 +216,25 @@ defmodule Pleroma.Web.Router do
scope "/packs" do
pipe_through(:admin_api)

get("/import", EmojiAPIController, :import_from_filesystem)
get("/remote", EmojiAPIController, :remote)
post("/download", EmojiAPIController, :download)
get("/import", EmojiPackController, :import_from_filesystem)
get("/remote", EmojiPackController, :remote)
post("/download", EmojiPackController, :download)

post("/:name", EmojiAPIController, :create)
patch("/:name", EmojiAPIController, :update)
delete("/:name", EmojiAPIController, :delete)
post("/:name", EmojiPackController, :create)
patch("/:name", EmojiPackController, :update)
delete("/:name", EmojiPackController, :delete)

post("/:name/files", EmojiAPIController, :add_file)
patch("/:name/files", EmojiAPIController, :update_file)
delete("/:name/files", EmojiAPIController, :delete_file)
post("/:name/files", EmojiPackController, :add_file)
patch("/:name/files", EmojiPackController, :update_file)
delete("/:name/files", EmojiPackController, :delete_file)
end

# Pack info / downloading
scope "/packs" do
get("/", EmojiAPIController, :list)
get("/:name", EmojiAPIController, :show)
get("/:name/archive", EmojiAPIController, :archive)
pipe_through(:api)
get("/", EmojiPackController, :index)
get("/:name", EmojiPackController, :show)
get("/:name/archive", EmojiPackController, :archive)
end
end

@@ -337,7 +338,7 @@ defmodule Pleroma.Web.Router do
get("/mascot", MascotController, :show)
put("/mascot", MascotController, :update)

post("/scrobble", ScrobbleController, :new_scrobble)
post("/scrobble", ScrobbleController, :create)
end

scope [] do
@@ -357,7 +358,7 @@ defmodule Pleroma.Web.Router do

scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
get("/accounts/:id/scrobbles", ScrobbleController, :user_scrobbles)
get("/accounts/:id/scrobbles", ScrobbleController, :index)
end

scope "/api/v1", Pleroma.Web.MastodonAPI do


+ 30
- 19
lib/pleroma/workers/attachments_cleanup_worker.ex View File

@@ -27,8 +27,20 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do

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
delete_ids =
object_ids_and_hrefs =
from(o in Object,
where:
fragment(
@@ -67,29 +79,28 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do
|> Enum.map(fn {href, %{id: id, count: count}} ->
# only delete files that have single instance
with 1 <- count do
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()),
"/"
)

file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
href
|> String.trim_leading("#{base_url}/#{prefix}")
|> uploader.delete_file()

uploader.delete_file(file_path)
{id, href}
else
_ -> {id, nil}
end

id
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()

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

def perform(%{"op" => "cleanup_attachments", "object" => _object}, _job), do: :ok
def perform(%{"op" => "cleanup_attachments", "object" => _object}, _job), do: {:ok, :skip}
end

+ 1
- 1
mix.exs View File

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


+ 3
- 3
mix.lock View File

@@ -21,13 +21,13 @@
"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"},
"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"},
"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"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"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_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"},
@@ -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"},
"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"},
"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"},
"jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm", "3c7ddc8a9394b92891db7c2771da94bf819834a1a4c92e30857b7d582e2f8257"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},


+ 1
- 1
priv/static/packs/arrow-key-navigation.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{722:function(e,t,n){"use strict";n.r(t),n.d(t,"register",(function(){return s})),n.d(t,"setFocusTrapTest",(function(){return d})),n.d(t,"unregister",(function(){return l}));var r="a[href], area[href], input, select, textarea, button, iframe, object, embed, [contenteditable], [tabindex], video[controls], audio[controls], summary",o=["text","search","url","password","tel"],i=["checkbox","radio"],a=void 0;function c(e){for(var t=[],n=(function(e){if(!a)return;var t=e.parentElement;for(;t;){if(a(t))return t;t=t.parentElement}}(e)||document).querySelectorAll(r),o=n.length,i=0;i<o;i++){var c=n[i];c!==e&&(c.disabled||/^-/.test(c.getAttribute("tabindex")||"")||c.hasAttribute("inert")||!(c.offsetWidth>0||c.offsetHeight>0))||t.push(c)}return t}function u(e,t){var n=document.activeElement;if(!function(e,t){var n,r,i,a=e.tagName,c="TEXTAREA"===a,u="INPUT"===a&&-1!==o.indexOf(e.getAttribute("type").toLowerCase()),f=e.hasAttribute("contenteditable");if(!c&&!u&&!f)return!1;if(f){var s=getSelection();n=s.anchorOffset,r=s.focusOffset,i=e.textContent.length}else n=e.selectionStart,r=e.selectionEnd,i=e.value.length;return("ArrowLeft"!==t||n!==r||0!==n)&&("ArrowRight"!==t||n!==r||n!==i)}(n,t)){var r=c(n);if(r.length){var i=r.indexOf(n);("ArrowLeft"===t?r[i-1]||r[0]:r[i+1]||r[r.length-1]).focus(),e.preventDefault()}}}function f(e){if(!(e.altKey||e.metaKey||e.ctrlKey)){var t=e.key;switch(t){case"ArrowLeft":case"ArrowRight":u(e,t);break;case"Enter":!function(e){var t=document.activeElement;"INPUT"===t.tagName&&-1!==i.indexOf(t.getAttribute("type").toLowerCase())&&(t.click(),e.preventDefault())}(e)}}}function s(){addEventListener("keydown",f)}function l(){removeEventListener("keydown",f)}function d(e){a=e}}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{738:function(e,t,n){"use strict";n.r(t),n.d(t,"register",(function(){return s})),n.d(t,"setFocusTrapTest",(function(){return d})),n.d(t,"unregister",(function(){return l}));var r="a[href], area[href], input, select, textarea, button, iframe, object, embed, [contenteditable], [tabindex], video[controls], audio[controls], summary",o=["text","search","url","password","tel"],i=["checkbox","radio"],a=void 0;function c(e){for(var t=[],n=(function(e){if(!a)return;var t=e.parentElement;for(;t;){if(a(t))return t;t=t.parentElement}}(e)||document).querySelectorAll(r),o=n.length,i=0;i<o;i++){var c=n[i];c!==e&&(c.disabled||/^-/.test(c.getAttribute("tabindex")||"")||c.hasAttribute("inert")||!(c.offsetWidth>0||c.offsetHeight>0))||t.push(c)}return t}function u(e,t){var n=document.activeElement;if(!function(e,t){var n,r,i,a=e.tagName,c="TEXTAREA"===a,u="INPUT"===a&&-1!==o.indexOf(e.getAttribute("type").toLowerCase()),f=e.hasAttribute("contenteditable");if(!c&&!u&&!f)return!1;if(f){var s=getSelection();n=s.anchorOffset,r=s.focusOffset,i=e.textContent.length}else n=e.selectionStart,r=e.selectionEnd,i=e.value.length;return("ArrowLeft"!==t||n!==r||0!==n)&&("ArrowRight"!==t||n!==r||n!==i)}(n,t)){var r=c(n);if(r.length){var i=r.indexOf(n);("ArrowLeft"===t?r[i-1]||r[0]:r[i+1]||r[r.length-1]).focus(),e.preventDefault()}}}function f(e){if(!(e.altKey||e.metaKey||e.ctrlKey)){var t=e.key;switch(t){case"ArrowLeft":case"ArrowRight":u(e,t);break;case"Enter":!function(e){var t=document.activeElement;"INPUT"===t.tagName&&-1!==i.indexOf(t.getAttribute("type").toLowerCase())&&(t.click(),e.preventDefault())}(e)}}}function s(){addEventListener("keydown",f)}function l(){removeEventListener("keydown",f)}function d(e){a=e}}}]);
//# sourceMappingURL=arrow-key-navigation.js.map

+ 2
- 2
priv/static/packs/base_polyfills.js
File diff suppressed because it is too large
View File


priv/static/packs/base_polyfills.js.LICENSE → priv/static/packs/base_polyfills.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/base_polyfills.js.map
File diff suppressed because it is too large
View File


+ 2
- 2
priv/static/packs/common.js
File diff suppressed because it is too large
View File


priv/static/packs/common.js.LICENSE → priv/static/packs/common.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/common.js.map
File diff suppressed because it is too large
View File


+ 2
- 2
priv/static/packs/containers/media_container.js
File diff suppressed because it is too large
View File


priv/static/packs/containers/media_container.js.LICENSE → priv/static/packs/containers/media_container.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/containers/media_container.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/admin.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/admin.js.map
File diff suppressed because it is too large
View File


+ 2
- 2
priv/static/packs/core/auth.js
File diff suppressed because it is too large
View File


priv/static/packs/core/auth.js.LICENSE → priv/static/packs/core/auth.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/core/auth.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/common.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/common.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/embed.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{918:function(e,t){window.addEventListener("message",(function(e){var t=e.data||{};function n(){window.parent.postMessage({type:"setHeight",id:t.id,height:document.getElementsByTagName("html")[0].scrollHeight},"*")}window.parent&&"setHeight"===t.type&&(["interactive","complete"].includes(document.readyState)?n():document.addEventListener("DOMContentLoaded",n))}))}},[[918,0]]]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{944:function(e,t){window.addEventListener("message",(function(e){var t=e.data||{};function n(){window.parent.postMessage({type:"setHeight",id:t.id,height:document.getElementsByTagName("html")[0].scrollHeight},"*")}window.parent&&"setHeight"===t.type&&(["interactive","complete"].includes(document.readyState)?n():document.addEventListener("DOMContentLoaded",n))}))}},[[944,0]]]);
//# sourceMappingURL=embed.js.map

+ 1
- 1
priv/static/packs/core/mailer.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{919:function(n,o,w){"use strict";w.r(o);w(920)},920:function(n,o,w){}},[[919,0]]]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{945:function(n,o,w){"use strict";w.r(o);w(946)},946:function(n,o,w){}},[[945,0]]]);
//# sourceMappingURL=mailer.js.map

+ 1
- 1
priv/static/packs/core/modal.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/modal.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/public.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/core/public.js.map
File diff suppressed because it is too large
View File


+ 2
- 2
priv/static/packs/core/settings.js
File diff suppressed because it is too large
View File


priv/static/packs/core/settings.js.LICENSE → priv/static/packs/core/settings.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/core/settings.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/emoji_picker.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{786:function(n,r,i){"use strict";i.r(r);var o=i(1055);i.d(r,"Picker",(function(){return o.a}));var c=i(1032);i.d(r,"Emoji",(function(){return c.a}))}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{812:function(n,r,i){"use strict";i.r(r);var o=i(1082);i.d(r,"Picker",(function(){return o.a}));var c=i(1058);i.d(r,"Emoji",(function(){return c.a}))}}]);
//# sourceMappingURL=emoji_picker.js.map

+ 2
- 2
priv/static/packs/extra_polyfills.js
File diff suppressed because it is too large
View File


priv/static/packs/extra_polyfills.js.LICENSE → priv/static/packs/extra_polyfills.js.LICENSE.txt View File


+ 1
- 1
priv/static/packs/extra_polyfills.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/account_gallery.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/account_gallery.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/account_timeline.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{793:function(t,a,e){"use strict";e.r(a),e.d(a,"default",(function(){return _}));var s,o,i,c=e(0),n=e(2),p=e(7),r=e(1),u=(e(3),e(13)),d=e(14),l=e.n(d),h=e(5),b=e.n(h),m=e(25),j=e(33),I=e(1038),O=e(300),f=e(731),w=e(1057),g=e(738),v=e(4),R=e(18),y=e(6),M=e(291),L=e(1030),S=Object(v.List)(),_=Object(u.connect)((function(t,a){var e=a.params.accountId,s=a.withReplies,o=void 0!==s&&s,i=o?e+":with_replies":e;return{isAccount:!!t.getIn(["accounts",e]),statusIds:t.getIn(["timelines","account:"+i,"items"],S),featuredStatusIds:o?Object(v.List)():t.getIn(["timelines","account:"+e+":pinned","items"],S),isLoading:t.getIn(["timelines","account:"+i,"isLoading"]),hasMore:t.getIn(["timelines","account:"+i,"hasMore"]),blockedBy:t.getIn(["relationships",e,"blocked_by"],!1)}}))((i=o=function(t){function a(){for(var a,e=arguments.length,s=new Array(e),o=0;o<e;o++)s[o]=arguments[o];return a=t.call.apply(t,[this].concat(s))||this,Object(r.a)(Object(n.a)(a),"handleLoadMore",(function(t){a.props.dispatch(Object(j.q)(a.props.params.accountId,{maxId:t,withReplies:a.props.withReplies}))})),a}Object(p.a)(a,t);var e=a.prototype;return e.componentWillMount=function(){var t=this.props,a=t.params.accountId,e=t.withReplies;this.props.dispatch(Object(m.A)(a)),this.props.dispatch(Object(M.d)(a)),e||this.props.dispatch(Object(j.o)(a)),this.props.dispatch(Object(j.q)(a,{withReplies:e}))},e.componentWillReceiveProps=function(t){(t.params.accountId!==this.props.params.accountId&&t.params.accountId||t.withReplies!==this.props.withReplies)&&(this.props.dispatch(Object(m.A)(t.params.accountId)),this.props.dispatch(Object(M.d)(t.params.accountId)),t.withReplies||this.props.dispatch(Object(j.o)(t.params.accountId)),this.props.dispatch(Object(j.q)(t.params.accountId,{withReplies:t.params.withReplies})))},e.render=function(){var t=this.props,a=t.shouldUpdateScroll,e=t.statusIds,s=t.featuredStatusIds,o=t.isLoading,i=t.hasMore,n=t.blockedBy,p=t.isAccount,r=t.multiColumn;if(!p)return Object(c.a)(f.a,{},void 0,Object(c.a)(g.a,{multiColumn:r}),Object(c.a)(L.a,{}));if(!e&&o)return Object(c.a)(f.a,{},void 0,Object(c.a)(O.a,{}));var u=n?Object(c.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(c.a)(y.b,{id:"empty_column.account_timeline",defaultMessage:"No toots here!"});return Object(c.a)(f.a,{},void 0,Object(c.a)(g.a,{multiColumn:r}),Object(c.a)(I.a,{prepend:Object(c.a)(w.a,{accountId:this.props.params.accountId}),alwaysPrepend:!0,scrollKey:"account_timeline",statusIds:n?S:e,featuredStatusIds:s,isLoading:o,hasMore:i,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:u,bindToDocument:!r}))},a}(R.a),Object(r.a)(o,"propTypes",{params:b.a.object.isRequired,dispatch:b.a.func.isRequired,shouldUpdateScroll:b.a.func,statusIds:l.a.list,featuredStatusIds:l.a.list,isLoading:b.a.bool,hasMore:b.a.bool,withReplies:b.a.bool,blockedBy:b.a.bool,isAccount:b.a.bool,multiColumn:b.a.bool}),s=i))||s}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{819:function(t,a,e){"use strict";e.r(a),e.d(a,"default",(function(){return _}));var s,o,i,c=e(0),n=e(2),p=(e(9),e(6),e(8)),r=e(1),u=(e(3),e(15)),d=e(16),l=e.n(d),h=e(5),b=e.n(h),m=e(26),j=e(36),I=e(1065),O=e(306),f=e(757),w=e(1084),v=e(764),g=e(4),R=e(21),y=e(7),M=e(291),L=e(1057);var S=Object(g.List)(),_=Object(u.connect)((function(t,a){var e=a.params.accountId,s=a.withReplies,o=void 0!==s&&s,i=o?e+":with_replies":e;return{isAccount:!!t.getIn(["accounts",e]),statusIds:t.getIn(["timelines","account:"+i,"items"],S),featuredStatusIds:o?Object(g.List)():t.getIn(["timelines","account:"+e+":pinned","items"],S),isLoading:t.getIn(["timelines","account:"+i,"isLoading"]),hasMore:t.getIn(["timelines","account:"+i,"hasMore"]),blockedBy:t.getIn(["relationships",e,"blocked_by"],!1)}}))((i=o=function(t){Object(p.a)(e,t);var a;a=e;function e(){for(var a,e=arguments.length,s=new Array(e),o=0;o<e;o++)s[o]=arguments[o];return a=t.call.apply(t,[this].concat(s))||this,Object(r.a)(Object(n.a)(a),"handleLoadMore",(function(t){a.props.dispatch(Object(j.q)(a.props.params.accountId,{maxId:t,withReplies:a.props.withReplies}))})),a}var s=e.prototype;return s.componentWillMount=function(){var t=this.props,a=t.params.accountId,e=t.withReplies;this.props.dispatch(Object(m.A)(a)),this.props.dispatch(Object(M.d)(a)),e||this.props.dispatch(Object(j.o)(a)),this.props.dispatch(Object(j.q)(a,{withReplies:e}))},s.componentWillReceiveProps=function(t){(t.params.accountId!==this.props.params.accountId&&t.params.accountId||t.withReplies!==this.props.withReplies)&&(this.props.dispatch(Object(m.A)(t.params.accountId)),this.props.dispatch(Object(M.d)(t.params.accountId)),t.withReplies||this.props.dispatch(Object(j.o)(t.params.accountId)),this.props.dispatch(Object(j.q)(t.params.accountId,{withReplies:t.params.withReplies})))},s.render=function(){var t=this.props,a=t.shouldUpdateScroll,e=t.statusIds,s=t.featuredStatusIds,o=t.isLoading,i=t.hasMore,n=t.blockedBy,p=t.isAccount,r=t.multiColumn;if(!p)return Object(c.a)(f.a,{},void 0,Object(c.a)(v.a,{multiColumn:r}),Object(c.a)(L.a,{}));if(!e&&o)return Object(c.a)(f.a,{},void 0,Object(c.a)(O.a,{}));var u=n?Object(c.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(c.a)(y.b,{id:"empty_column.account_timeline",defaultMessage:"No toots here!"});return(Object(c.a)(f.a,{},void 0,Object(c.a)(v.a,{multiColumn:r}),Object(c.a)(I.a,{prepend:Object(c.a)(w.a,{accountId:this.props.params.accountId}),alwaysPrepend:!0,scrollKey:"account_timeline",statusIds:n?S:e,featuredStatusIds:s,isLoading:o,hasMore:i,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:u,bindToDocument:!r,timelineId:"account"})))},e}(R.a),Object(r.a)(o,"propTypes",{params:b.a.object.isRequired,dispatch:b.a.func.isRequired,shouldUpdateScroll:b.a.func,statusIds:l.a.list,featuredStatusIds:l.a.list,isLoading:b.a.bool,hasMore:b.a.bool,withReplies:b.a.bool,blockedBy:b.a.bool,isAccount:b.a.bool,multiColumn:b.a.bool}),s=i))||s}}]);
//# sourceMappingURL=account_timeline.js.map

+ 1
- 1
priv/static/packs/features/account_timeline.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/blocks.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{801:function(e,t,o){"use strict";o.r(t),o.d(t,"default",(function(){return q}));var a,n,c,s=o(0),r=o(2),i=o(7),u=o(1),l=o(62),d=o.n(l),b=(o(3),o(13)),p=o(6),h=o(18),f=o(14),j=o.n(f),O=o(5),m=o.n(O),g=o(300),M=o(731),k=o(737),v=o(1026),y=o(226),w=o(1023),I=Object(p.f)({heading:{id:"column.blocks",defaultMessage:"Blocked users"}}),q=Object(b.connect)((function(e){return{accountIds:e.getIn(["user_lists","blocks","items"]),hasMore:!!e.getIn(["user_lists","blocks","next"])}}))(a=Object(p.g)((c=n=function(e){function t(){for(var t,o=arguments.length,a=new Array(o),n=0;n<o;n++)a[n]=arguments[n];return t=e.call.apply(e,[this].concat(a))||this,Object(u.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(y.d)())}),300,{leading:!0})),t}Object(i.a)(t,e);var o=t.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(y.e)())},o.render=function(){var e=this.props,t=e.intl,o=e.accountIds,a=e.shouldUpdateScroll,n=e.hasMore,c=e.multiColumn;if(!o)return Object(s.a)(M.a,{},void 0,Object(s.a)(g.a,{}));var r=Object(s.a)(p.b,{id:"empty_column.blocks",defaultMessage:"You haven't blocked any users yet."});return Object(s.a)(M.a,{bindToDocument:!c,icon:"ban",heading:t.formatMessage(I.heading)},void 0,Object(s.a)(k.a,{}),Object(s.a)(w.a,{scrollKey:"blocks",onLoadMore:this.handleLoadMore,hasMore:n,shouldUpdateScroll:a,emptyMessage:r,bindToDocument:!c},void 0,o.map((function(e){return Object(s.a)(v.a,{id:e},e)}))))},t}(h.a),Object(u.a)(n,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,intl:m.a.object.isRequired,multiColumn:m.a.bool}),a=c))||a)||a}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{827:function(e,t,a){"use strict";a.r(t),a.d(t,"default",(function(){return q}));var o,n,c,s=a(0),r=a(2),i=(a(9),a(6),a(8)),u=a(1),l=a(65),d=a.n(l),b=(a(3),a(15)),p=a(7),h=a(21),f=a(16),j=a.n(f),O=a(5),m=a.n(O),g=a(306),M=a(757),v=a(763),k=a(1053),y=a(230),w=a(1049);var I=Object(p.f)({heading:{id:"column.blocks",defaultMessage:"Blocked users"}}),q=Object(b.connect)((function(e){return{accountIds:e.getIn(["user_lists","blocks","items"]),hasMore:!!e.getIn(["user_lists","blocks","next"])}}))(o=Object(p.g)((c=n=function(e){Object(i.a)(a,e);var t;t=a;function a(){for(var t,a=arguments.length,o=new Array(a),n=0;n<a;n++)o[n]=arguments[n];return t=e.call.apply(e,[this].concat(o))||this,Object(u.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(y.d)())}),300,{leading:!0})),t}var o=a.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(y.e)())},o.render=function(){var e=this.props,t=e.intl,a=e.accountIds,o=e.shouldUpdateScroll,n=e.hasMore,c=e.multiColumn;if(!a)return Object(s.a)(M.a,{},void 0,Object(s.a)(g.a,{}));var r=Object(s.a)(p.b,{id:"empty_column.blocks",defaultMessage:"You haven't blocked any users yet."});return(Object(s.a)(M.a,{bindToDocument:!c,icon:"ban",heading:t.formatMessage(I.heading)},void 0,Object(s.a)(v.a,{}),Object(s.a)(w.a,{scrollKey:"blocks",onLoadMore:this.handleLoadMore,hasMore:n,shouldUpdateScroll:o,emptyMessage:r,bindToDocument:!c},void 0,a.map((function(e){return Object(s.a)(k.a,{id:e},e)})))))},a}(h.a),Object(u.a)(n,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,intl:m.a.object.isRequired,multiColumn:m.a.bool}),o=c))||o)||o}}]);
//# sourceMappingURL=blocks.js.map

+ 1
- 1
priv/static/packs/features/blocks.js.map View File

@@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/mastodon/features/blocks/index.js"],"names":["messages","defineMessages","heading","Blocks","connect","state","accountIds","getIn","hasMore","injectIntl","props","dispatch","expandBlocks","leading","componentWillMount","this","fetchBlocks","render","intl","shouldUpdateScroll","multiColumn","emptyMessage","id","defaultMessage","bindToDocument","icon","formatMessage","scrollKey","onLoadMore","handleLoadMore","map","ImmutablePureComponent","params","PropTypes","object","isRequired","func","ImmutablePropTypes","list","bool"],"mappings":"wTAcMA,EAAWC,YAAe,CAC9BC,QAAQ,CAAD,qDAUHC,EAFUC,mBALQ,SAAAC,GAAK,MAAK,CAChCC,WAAYD,EAAME,MAAM,CAAC,aAAc,SAAU,UACjDC,UAAWH,EAAME,MAAM,CAAC,aAAc,SAAU,Y,GAIjDE,a,mMAiBkB,KAAS,WACxB,EAAKC,MAAMC,SAASC,iBACnB,IAAK,CAAEC,SAAS,K,8CANnBC,mBAAA,WACEC,KAAKL,MAAMC,SAASK,gB,EAOtBC,OAAA,WAAW,IAAD,EAC+DF,KAAKL,MAApEQ,EADA,EACAA,KAAMZ,EADN,EACMA,WAAYa,EADlB,EACkBA,mBAAoBX,EADtC,EACsCA,QAASY,EAD/C,EAC+CA,YAEvD,IAAKd,EACH,OACE,YAAC,IAAD,UACE,YAAC,IAAD,KAKN,IAAMe,EAAe,YAAC,IAAD,CAAkBC,GAAG,sBAAsBC,eAAe,uCAE/E,OACE,YAAC,IAAD,CAAQC,gBAAiBJ,EAAaK,KAAK,MAAMvB,QAASgB,EAAKQ,cAAc1B,EAASE,eAAtF,EACE,YAAC,IAAD,IACA,YAAC,IAAD,CACEyB,UAAU,SACVC,WAAYb,KAAKc,eACjBrB,QAASA,EACTW,mBAAoBA,EACpBE,aAAcA,EACdG,gBAAiBJ,QANnB,EAQGd,EAAWwB,KAAI,SAAAR,GAAE,OAChB,YAAC,IAAD,CAA2BA,GAAIA,GAARA,S,GA7CdS,K,0BAEA,CACjBC,OAAQC,IAAUC,OAAOC,WACzBxB,SAAUsB,IAAUG,KAAKD,WACzBhB,mBAAoBc,IAAUG,KAC9B9B,WAAY+B,IAAmBC,KAC/B9B,QAASyB,IAAUM,KACnBrB,KAAMe,IAAUC,OAAOC,WACvBf,YAAaa,IAAUM,O","file":"features/blocks.js","sourcesContent":["import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport PropTypes from 'prop-types';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport AccountContainer from '../../containers/account_container';\nimport { fetchBlocks, expandBlocks } from '../../actions/blocks';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },\n});\n\nconst mapStateToProps = state => ({\n accountIds: state.getIn(['user_lists', 'blocks', 'items']),\n hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Blocks extends ImmutablePureComponent {\n\n static propTypes = {\n params: PropTypes.object.isRequired,\n dispatch: PropTypes.func.isRequired,\n shouldUpdateScroll: PropTypes.func,\n accountIds: ImmutablePropTypes.list,\n hasMore: PropTypes.bool,\n intl: PropTypes.object.isRequired,\n multiColumn: PropTypes.bool,\n };\n\n componentWillMount () {\n this.props.dispatch(fetchBlocks());\n }\n\n handleLoadMore = debounce(() => {\n this.props.dispatch(expandBlocks());\n }, 300, { leading: true });\n\n render () {\n const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn } = this.props;\n\n if (!accountIds) {\n return (\n <Column>\n <LoadingIndicator />\n </Column>\n );\n }\n\n const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage=\"You haven't blocked any users yet.\" />;\n\n return (\n <Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>\n <ColumnBackButtonSlim />\n <ScrollableList\n scrollKey='blocks'\n onLoadMore={this.handleLoadMore}\n hasMore={hasMore}\n shouldUpdateScroll={shouldUpdateScroll}\n emptyMessage={emptyMessage}\n bindToDocument={!multiColumn}\n >\n {accountIds.map(id =>\n <AccountContainer key={id} id={id} />\n )}\n </ScrollableList>\n </Column>\n );\n }\n\n}\n"],"sourceRoot":""}
{"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/mastodon/features/blocks/index.js"],"names":["messages","defineMessages","heading","Blocks","connect","state","accountIds","getIn","hasMore","injectIntl","props","dispatch","expandBlocks","leading","componentWillMount","this","fetchBlocks","render","intl","shouldUpdateScroll","multiColumn","emptyMessage","id","defaultMessage","bindToDocument","icon","formatMessage","scrollKey","onLoadMore","handleLoadMore","map","ImmutablePureComponent","params","PropTypes","object","isRequired","func","ImmutablePropTypes","list","bool"],"mappings":"oUAcA,IAAMA,EAAWC,YAAe,CAC9BC,QAAQ,CAAD,qDAUHC,EAFUC,mBALQ,SAAAC,GAAK,MAAK,CAChCC,WAAYD,EAAME,MAAM,CAAC,aAAc,SAAU,UACjDC,UAAWH,EAAME,MAAM,CAAC,aAAc,SAAU,Y,GAIjDE,a,8NAiBkB,KAAS,WACxB,EAAKC,MAAMC,SAASC,iBACnB,IAAK,CAAEC,SAAS,K,6BANnBC,mBAAA,WACEC,KAAKL,MAAMC,SAASK,gB,EAOtBC,OAAA,WAAW,IAAD,EAC+DF,KAAKL,MAApEQ,EADA,EACAA,KAAMZ,EADN,EACMA,WAAYa,EADlB,EACkBA,mBAAoBX,EADtC,EACsCA,QAASY,EAD/C,EAC+CA,YAEvD,IAAKd,EACH,OACE,YAAC,IAAD,UACE,YAAC,IAAD,KAKN,IAAMe,EAAe,YAAC,IAAD,CAAkBC,GAAG,sBAAsBC,eAAe,uCAE/E,OACE,YAAC,IAAD,CAAQC,gBAAiBJ,EAAaK,KAAK,MAAMvB,QAASgB,EAAKQ,cAAc1B,EAASE,eAAtF,EACE,YAAC,IAAD,IACA,YAAC,IAAD,CACEyB,UAAU,SACVC,WAAYb,KAAKc,eACjBrB,QAASA,EACTW,mBAAoBA,EACpBE,aAAcA,EACdG,gBAAiBJ,QANnB,EAQGd,EAAWwB,KAAI,SAAAR,GAAE,OAChB,YAAC,IAAD,CAA2BA,GAAIA,GAARA,U,GA7CdS,K,0BAEA,CACjBC,OAAQC,IAAUC,OAAOC,WACzBxB,SAAUsB,IAAUG,KAAKD,WACzBhB,mBAAoBc,IAAUG,KAC9B9B,WAAY+B,IAAmBC,KAC/B9B,QAASyB,IAAUM,KACnBrB,KAAMe,IAAUC,OAAOC,WACvBf,YAAaa,IAAUM,O","file":"features/blocks.js","sourcesContent":["import React from 'react';\nimport { connect } from 'react-redux';\nimport { defineMessages, injectIntl, FormattedMessage } from 'react-intl';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport { debounce } from 'lodash';\nimport PropTypes from 'prop-types';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport Column from '../ui/components/column';\nimport ColumnBackButtonSlim from '../../components/column_back_button_slim';\nimport AccountContainer from '../../containers/account_container';\nimport { fetchBlocks, expandBlocks } from '../../actions/blocks';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst messages = defineMessages({\n heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },\n});\n\nconst mapStateToProps = state => ({\n accountIds: state.getIn(['user_lists', 'blocks', 'items']),\n hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),\n});\n\nexport default @connect(mapStateToProps)\n@injectIntl\nclass Blocks extends ImmutablePureComponent {\n\n static propTypes = {\n params: PropTypes.object.isRequired,\n dispatch: PropTypes.func.isRequired,\n shouldUpdateScroll: PropTypes.func,\n accountIds: ImmutablePropTypes.list,\n hasMore: PropTypes.bool,\n intl: PropTypes.object.isRequired,\n multiColumn: PropTypes.bool,\n };\n\n componentWillMount () {\n this.props.dispatch(fetchBlocks());\n }\n\n handleLoadMore = debounce(() => {\n this.props.dispatch(expandBlocks());\n }, 300, { leading: true });\n\n render () {\n const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn } = this.props;\n\n if (!accountIds) {\n return (\n <Column>\n <LoadingIndicator />\n </Column>\n );\n }\n\n const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage=\"You haven't blocked any users yet.\" />;\n\n return (\n <Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>\n <ColumnBackButtonSlim />\n <ScrollableList\n scrollKey='blocks'\n onLoadMore={this.handleLoadMore}\n hasMore={hasMore}\n shouldUpdateScroll={shouldUpdateScroll}\n emptyMessage={emptyMessage}\n bindToDocument={!multiColumn}\n >\n {accountIds.map(id =>\n <AccountContainer key={id} id={id} />,\n )}\n </ScrollableList>\n </Column>\n );\n }\n\n}\n"],"sourceRoot":""}

+ 1
- 1
priv/static/packs/features/bookmarked_statuses.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{800:function(t,e,o){"use strict";o.r(e),o.d(e,"default",(function(){return C}));var a,n,s,i=o(0),c=o(2),l=o(7),r=o(1),d=o(62),u=o.n(d),b=o(3),h=o.n(b),p=o(13),m=o(5),k=o.n(m),O=o(14),f=o.n(O),j=o(205),g=o(731),M=o(733),I=o(250),v=o(1038),w=o(6),y=o(18),L=Object(w.f)({heading:{id:"column.bookmarks",defaultMessage:"Bookmarks"}}),C=Object(p.connect)((function(t){return{statusIds:t.getIn(["status_lists","bookmarks","items"]),isLoading:t.getIn(["status_lists","bookmarks","isLoading"],!0),hasMore:!!t.getIn(["status_lists","bookmarks","next"])}}))(a=Object(w.g)((s=n=function(t){function e(){for(var e,o=arguments.length,a=new Array(o),n=0;n<o;n++)a[n]=arguments[n];return e=t.call.apply(t,[this].concat(a))||this,Object(r.a)(Object(c.a)(e),"handlePin",(function(){var t=e.props,o=t.columnId,a=t.dispatch;a(o?Object(I.h)(o):Object(I.e)("BOOKMARKS",{}))})),Object(r.a)(Object(c.a)(e),"handleMove",(function(t){var o=e.props,a=o.columnId;(0,o.dispatch)(Object(I.g)(a,t))})),Object(r.a)(Object(c.a)(e),"handleHeaderClick",(function(){e.column.scrollTop()})),Object(r.a)(Object(c.a)(e),"setRef",(function(t){e.column=t})),Object(r.a)(Object(c.a)(e),"handleLoadMore",u()((function(){e.props.dispatch(Object(j.g)())}),300,{leading:!0})),e}Object(l.a)(e,t);var o=e.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(j.h)())},o.render=function(){var t=this.props,e=t.intl,o=t.shouldUpdateScroll,a=t.statusIds,n=t.columnId,s=t.multiColumn,c=t.hasMore,l=t.isLoading,r=!!n,d=Object(i.a)(w.b,{id:"empty_column.bookmarked_statuses",defaultMessage:"You don't have any bookmarked toots yet. When you bookmark one, it will show up here."});return h.a.createElement(g.a,{bindToDocument:!s,ref:this.setRef,label:e.formatMessage(L.heading)},Object(i.a)(M.a,{icon:"bookmark",title:e.formatMessage(L.heading),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:r,multiColumn:s,showBackButton:!0}),Object(i.a)(v.a,{trackScroll:!r,statusIds:a,scrollKey:"bookmarked_statuses-"+n,hasMore:c,isLoading:l,onLoadMore:this.handleLoadMore,shouldUpdateScroll:o,emptyMessage:d,bindToDocument:!s}))},e}(y.a),Object(r.a)(n,"propTypes",{dispatch:k.a.func.isRequired,shouldUpdateScroll:k.a.func,statusIds:f.a.list.isRequired,intl:k.a.object.isRequired,columnId:k.a.string,multiColumn:k.a.bool,hasMore:k.a.bool,isLoading:k.a.bool}),a=s))||a)||a}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{826:function(t,e,o){"use strict";o.r(e),o.d(e,"default",(function(){return C}));var a,n,s,i=o(0),c=o(2),r=(o(9),o(6),o(8)),l=o(1),d=o(65),u=o.n(d),b=o(3),h=o.n(b),p=o(15),m=o(5),k=o.n(m),O=o(16),f=o.n(O),j=o(209),g=o(757),M=o(759),v=o(253),I=o(1065),w=o(7),y=o(21);var L=Object(w.f)({heading:{id:"column.bookmarks",defaultMessage:"Bookmarks"}}),C=Object(p.connect)((function(t){return{statusIds:t.getIn(["status_lists","bookmarks","items"]),isLoading:t.getIn(["status_lists","bookmarks","isLoading"],!0),hasMore:!!t.getIn(["status_lists","bookmarks","next"])}}))(a=Object(w.g)((s=n=function(t){Object(r.a)(o,t);var e;e=o;function o(){for(var e,o=arguments.length,a=new Array(o),n=0;n<o;n++)a[n]=arguments[n];return e=t.call.apply(t,[this].concat(a))||this,Object(l.a)(Object(c.a)(e),"handlePin",(function(){var t=e.props,o=t.columnId,a=t.dispatch;a(o?Object(v.h)(o):Object(v.e)("BOOKMARKS",{}))})),Object(l.a)(Object(c.a)(e),"handleMove",(function(t){var o=e.props,a=o.columnId;(0,o.dispatch)(Object(v.g)(a,t))})),Object(l.a)(Object(c.a)(e),"handleHeaderClick",(function(){e.column.scrollTop()})),Object(l.a)(Object(c.a)(e),"setRef",(function(t){e.column=t})),Object(l.a)(Object(c.a)(e),"handleLoadMore",u()((function(){e.props.dispatch(Object(j.g)())}),300,{leading:!0})),e}var a=o.prototype;return a.componentWillMount=function(){this.props.dispatch(Object(j.h)())},a.render=function(){var t=this.props,e=t.intl,o=t.shouldUpdateScroll,a=t.statusIds,n=t.columnId,s=t.multiColumn,c=t.hasMore,r=t.isLoading,l=!!n,d=Object(i.a)(w.b,{id:"empty_column.bookmarked_statuses",defaultMessage:"You don't have any bookmarked toots yet. When you bookmark one, it will show up here."});return h.a.createElement(g.a,{bindToDocument:!s,ref:this.setRef,label:e.formatMessage(L.heading)},Object(i.a)(M.a,{icon:"bookmark",title:e.formatMessage(L.heading),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:l,multiColumn:s,showBackButton:!0}),Object(i.a)(I.a,{trackScroll:!l,statusIds:a,scrollKey:"bookmarked_statuses-"+n,hasMore:c,isLoading:r,onLoadMore:this.handleLoadMore,shouldUpdateScroll:o,emptyMessage:d,bindToDocument:!s}))},o}(y.a),Object(l.a)(n,"propTypes",{dispatch:k.a.func.isRequired,shouldUpdateScroll:k.a.func,statusIds:f.a.list.isRequired,intl:k.a.object.isRequired,columnId:k.a.string,multiColumn:k.a.bool,hasMore:k.a.bool,isLoading:k.a.bool}),a=s))||a)||a}}]);
//# sourceMappingURL=bookmarked_statuses.js.map

+ 1
- 1
priv/static/packs/features/bookmarked_statuses.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/community_timeline.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{835:function(e,t,n){"use strict";n.r(t);var o,i,c,a=n(0),l=n(2),d=n(7),r=n(1),s=n(3),u=n.n(s),m=n(13),p=n(6),h=n(5),b=n.n(h),f=n(1036),y=n(736),j=n(733),O=n(33),M=n(250),g=n(1139),v=n(70),I=Object(m.connect)((function(e,t){var n=t.columnId,o=e.getIn(["settings","columns"]),i=o.findIndex((function(e){return e.get("uuid")===n}));return{settings:n&&i>=0?o.get(i).get("params"):e.getIn(["settings","community"])}}),(function(e,t){var n=t.columnId;return{onChange:function(t,o){e(n?Object(M.f)(n,t,o):Object(v.c)(["community"].concat(t),o))}}}))(g.a),C=n(740);n.d(t,"default",(function(){return U}));var w=Object(p.f)({title:{id:"column.community",defaultMessage:"Local timeline"}}),U=Object(m.connect)((function(e,t){var n=t.columnId,o=n,i=e.getIn(["settings","columns"]),c=i.findIndex((function(e){return e.get("uuid")===o})),a=n&&c>=0?i.get(c).getIn(["params","other","onlyMedia"]):e.getIn(["settings","community","other","onlyMedia"]),l=e.getIn(["timelines","community"+(a?":media":"")]);return{hasUnread:!!l&&l.get("unread")>0,onlyMedia:a}}))(o=Object(p.g)((c=i=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];return t=e.call.apply(e,[this].concat(o))||this,Object(r.a)(Object(l.a)(t),"handlePin",(function(){var e=t.props,n=e.columnId,o=e.dispatch,i=e.onlyMedia;o(n?Object(M.h)(n):Object(M.e)("COMMUNITY",{other:{onlyMedia:i}}))})),Object(r.a)(Object(l.a)(t),"handleMove",(function(e){var n=t.props,o=n.columnId;(0,n.dispatch)(Object(M.g)(o,e))})),Object(r.a)(Object(l.a)(t),"handleHeaderClick",(function(){t.column.scrollTop()})),Object(r.a)(Object(l.a)(t),"setRef",(function(e){t.column=e})),Object(r.a)(Object(l.a)(t),"handleLoadMore",(function(e){var n=t.props,o=n.dispatch,i=n.onlyMedia;o(Object(O.r)({maxId:e,onlyMedia:i}))})),t}Object(d.a)(t,e);var n=t.prototype;return n.componentDidMount=function(){var e=this.props,t=e.dispatch,n=e.onlyMedia;t(Object(O.r)({onlyMedia:n})),this.disconnect=t(Object(C.a)({onlyMedia:n}))},n.componentDidUpdate=function(e){if(e.onlyMedia!==this.props.onlyMedia){var t=this.props,n=t.dispatch,o=t.onlyMedia;this.disconnect(),n(Object(O.r)({onlyMedia:o})),this.disconnect=n(Object(C.a)({onlyMedia:o}))}},n.componentWillUnmount=function(){this.disconnect&&(this.disconnect(),this.disconnect=null)},n.render=function(){var e=this.props,t=e.intl,n=e.shouldUpdateScroll,o=e.hasUnread,i=e.columnId,c=e.multiColumn,l=e.onlyMedia,d=!!i;return u.a.createElement(y.a,{bindToDocument:!c,ref:this.setRef,label:t.formatMessage(w.title)},Object(a.a)(j.a,{icon:"users",active:o,title:t.formatMessage(w.title),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:d,multiColumn:c},void 0,Object(a.a)(I,{columnId:i})),Object(a.a)(f.a,{trackScroll:!d,scrollKey:"community_timeline-"+i,timelineId:"community"+(l?":media":""),onLoadMore:this.handleLoadMore,emptyMessage:Object(a.a)(p.b,{id:"empty_column.community",defaultMessage:"The local timeline is empty. Write something publicly to get the ball rolling!"}),shouldUpdateScroll:n,bindToDocument:!c}))},t}(u.a.PureComponent),Object(r.a)(i,"contextTypes",{router:b.a.object}),Object(r.a)(i,"defaultProps",{onlyMedia:!1}),o=c))||o)||o}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{861:function(e,t,n){"use strict";n.r(t),n.d(t,"default",(function(){return U}));var o,i,c,a=n(0),l=n(2),d=(n(9),n(6),n(8)),r=n(1),s=n(3),u=n.n(s),m=n(15),p=n(7),h=n(5),b=n.n(h),f=n(1063),y=n(762),j=n(759),O=n(36),M=n(253),g=n(1172),v=n(74),I=Object(m.connect)((function(e,t){var n=t.columnId,o=e.getIn(["settings","columns"]),i=o.findIndex((function(e){return e.get("uuid")===n}));return{settings:n&&i>=0?o.get(i).get("params"):e.getIn(["settings","community"])}}),(function(e,t){var n=t.columnId;return{onChange:function(t,o){e(n?Object(M.f)(n,t,o):Object(v.c)(["community"].concat(t),o))}}}))(g.a),C=n(766);var w=Object(p.f)({title:{id:"column.community",defaultMessage:"Local timeline"}}),U=Object(m.connect)((function(e,t){var n=t.columnId,o=n,i=e.getIn(["settings","columns"]),c=i.findIndex((function(e){return e.get("uuid")===o})),a=n&&c>=0?i.get(c).getIn(["params","other","onlyMedia"]):e.getIn(["settings","community","other","onlyMedia"]),l=e.getIn(["timelines","community"+(a?":media":"")]);return{hasUnread:!!l&&l.get("unread")>0,onlyMedia:a}}))(o=Object(p.g)((c=i=function(e){Object(d.a)(n,e);var t;t=n;function n(){for(var t,n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];return t=e.call.apply(e,[this].concat(o))||this,Object(r.a)(Object(l.a)(t),"handlePin",(function(){var e=t.props,n=e.columnId,o=e.dispatch,i=e.onlyMedia;o(n?Object(M.h)(n):Object(M.e)("COMMUNITY",{other:{onlyMedia:i}}))})),Object(r.a)(Object(l.a)(t),"handleMove",(function(e){var n=t.props,o=n.columnId;(0,n.dispatch)(Object(M.g)(o,e))})),Object(r.a)(Object(l.a)(t),"handleHeaderClick",(function(){t.column.scrollTop()})),Object(r.a)(Object(l.a)(t),"setRef",(function(e){t.column=e})),Object(r.a)(Object(l.a)(t),"handleLoadMore",(function(e){var n=t.props,o=n.dispatch,i=n.onlyMedia;o(Object(O.r)({maxId:e,onlyMedia:i}))})),t}var o=n.prototype;return o.componentDidMount=function(){var e=this.props,t=e.dispatch,n=e.onlyMedia;t(Object(O.r)({onlyMedia:n})),this.disconnect=t(Object(C.a)({onlyMedia:n}))},o.componentDidUpdate=function(e){if(e.onlyMedia!==this.props.onlyMedia){var t=this.props,n=t.dispatch,o=t.onlyMedia;this.disconnect(),n(Object(O.r)({onlyMedia:o})),this.disconnect=n(Object(C.a)({onlyMedia:o}))}},o.componentWillUnmount=function(){this.disconnect&&(this.disconnect(),this.disconnect=null)},o.render=function(){var e=this.props,t=e.intl,n=e.shouldUpdateScroll,o=e.hasUnread,i=e.columnId,c=e.multiColumn,l=e.onlyMedia,d=!!i;return u.a.createElement(y.a,{bindToDocument:!c,ref:this.setRef,label:t.formatMessage(w.title)},Object(a.a)(j.a,{icon:"users",active:o,title:t.formatMessage(w.title),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:d,multiColumn:c},void 0,Object(a.a)(I,{columnId:i})),Object(a.a)(f.a,{trackScroll:!d,scrollKey:"community_timeline-"+i,timelineId:"community"+(l?":media":""),onLoadMore:this.handleLoadMore,emptyMessage:Object(a.a)(p.b,{id:"empty_column.community",defaultMessage:"The local timeline is empty. Write something publicly to get the ball rolling!"}),shouldUpdateScroll:n,bindToDocument:!c}))},n}(u.a.PureComponent),Object(r.a)(i,"contextTypes",{router:b.a.object}),Object(r.a)(i,"defaultProps",{onlyMedia:!1}),o=c))||o)||o}}]);
//# sourceMappingURL=community_timeline.js.map

+ 1
- 1
priv/static/packs/features/community_timeline.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/compose.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/compose.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/direct_timeline.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/direct_timeline.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/directory.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/directory.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/domain_blocks.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{826:function(n,e,o){"use strict";o.r(e);var a,t,i,c,r,s,d=o(0),l=o(2),u=o(7),m=o(1),b=o(62),f=o.n(b),p=(o(3),o(13)),j=o(6),O=o(18),h=o(5),g=o.n(h),k=o(14),v=o.n(k),M=o(300),y=o(731),_=o(737),D=o(80),w=o(50),U=Object(j.f)({unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unhide {domain}"}}),C=Object(j.g)((i=t=function(n){function e(){for(var e,o=arguments.length,a=new Array(o),t=0;t<o;t++)a[t]=arguments[t];return e=n.call.apply(n,[this].concat(a))||this,Object(m.a)(Object(l.a)(e),"handleDomainUnblock",(function(){e.props.onUnblockDomain(e.props.domain)})),e}return Object(u.a)(e,n),e.prototype.render=function(){var n=this.props,e=n.domain,o=n.intl;return Object(d.a)("div",{className:"domain"},void 0,Object(d.a)("div",{className:"domain__wrapper"},void 0,Object(d.a)("span",{className:"domain__domain-name"},void 0,Object(d.a)("strong",{},void 0,e)),Object(d.a)("div",{className:"domain__buttons"},void 0,Object(d.a)(w.a,{active:!0,icon:"unlock",title:o.formatMessage(U.unblockDomain,{domain:e}),onClick:this.handleDomainUnblock}))))},e}(O.a),Object(m.a)(t,"propTypes",{domain:g.a.string,onUnblockDomain:g.a.func.isRequired,intl:g.a.object.isRequired}),a=i))||a,R=o(47),q=Object(j.f)({blockDomainConfirm:{id:"confirmations.domain_block.confirm",defaultMessage:"Hide entire domain"}}),N=Object(j.g)(Object(p.connect)((function(){return function(){return{}}}),(function(n,e){var o=e.intl;return{onBlockDomain:function(e){n(Object(R.d)("CONFIRM",{message:Object(d.a)(j.b,{id:"confirmations.domain_block.message",defaultMessage:"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",values:{domain:Object(d.a)("strong",{},void 0,e)}}),confirm:o.formatMessage(q.blockDomainConfirm),onConfirm:function(){return n(Object(D.e)(e))}}))},onUnblockDomain:function(e){n(Object(D.h)(e))}}}))(C)),T=o(1023);o.d(e,"default",(function(){return S}));var I=Object(j.f)({heading:{id:"column.domain_blocks",defaultMessage:"Hidden domains"},unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unhide {domain}"}}),S=Object(p.connect)((function(n){return{domains:n.getIn(["domain_lists","blocks","items"]),hasMore:!!n.getIn(["domain_lists","blocks","next"])}}))(c=Object(j.g)((s=r=function(n){function e(){for(var e,o=arguments.length,a=new Array(o),t=0;t<o;t++)a[t]=arguments[t];return e=n.call.apply(n,[this].concat(a))||this,Object(m.a)(Object(l.a)(e),"handleLoadMore",f()((function(){e.props.dispatch(Object(D.f)())}),300,{leading:!0})),e}Object(u.a)(e,n);var o=e.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(D.g)())},o.render=function(){var n=this.props,e=n.intl,o=n.domains,a=n.shouldUpdateScroll,t=n.hasMore,i=n.multiColumn;if(!o)return Object(d.a)(y.a,{},void 0,Object(d.a)(M.a,{}));var c=Object(d.a)(j.b,{id:"empty_column.domain_blocks",defaultMessage:"There are no hidden domains yet."});return Object(d.a)(y.a,{bindToDocument:!i,icon:"minus-circle",heading:e.formatMessage(I.heading)},void 0,Object(d.a)(_.a,{}),Object(d.a)(T.a,{scrollKey:"domain_blocks",onLoadMore:this.handleLoadMore,hasMore:t,shouldUpdateScroll:a,emptyMessage:c,bindToDocument:!i},void 0,o.map((function(n){return Object(d.a)(N,{domain:n},n)}))))},e}(O.a),Object(m.a)(r,"propTypes",{params:g.a.object.isRequired,dispatch:g.a.func.isRequired,shouldUpdateScroll:g.a.func,hasMore:g.a.bool,domains:v.a.orderedSet,intl:g.a.object.isRequired,multiColumn:g.a.bool}),c=s))||c)||c}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{852:function(n,o,a){"use strict";a.r(o),a.d(o,"default",(function(){return S}));var e,t,i,c=a(0),r=a(2),s=(a(9),a(6),a(8)),d=a(1),l=a(65),u=a.n(l),m=(a(3),a(15)),b=a(7),f=a(21),p=a(5),j=a.n(p),O=a(16),h=a.n(O),k=a(306),g=a(757),v=a(763),M=a(84),y=a(53);var _,D,w,U=Object(b.f)({unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unblock domain {domain}"}}),C=Object(b.g)((i=t=function(n){Object(s.a)(a,n);var o;o=a;function a(){for(var o,a=arguments.length,e=new Array(a),t=0;t<a;t++)e[t]=arguments[t];return o=n.call.apply(n,[this].concat(e))||this,Object(d.a)(Object(r.a)(o),"handleDomainUnblock",(function(){o.props.onUnblockDomain(o.props.domain)})),o}return a.prototype.render=function(){var n=this.props,o=n.domain,a=n.intl;return(Object(c.a)("div",{className:"domain"},void 0,Object(c.a)("div",{className:"domain__wrapper"},void 0,Object(c.a)("span",{className:"domain__domain-name"},void 0,Object(c.a)("strong",{},void 0,o)),Object(c.a)("div",{className:"domain__buttons"},void 0,Object(c.a)(y.a,{active:!0,icon:"unlock",title:a.formatMessage(U.unblockDomain,{domain:o}),onClick:this.handleDomainUnblock})))))},a}(f.a),Object(d.a)(t,"propTypes",{domain:j.a.string,onUnblockDomain:j.a.func.isRequired,intl:j.a.object.isRequired}),e=i))||e,R=a(48),q=Object(b.f)({blockDomainConfirm:{id:"confirmations.domain_block.confirm",defaultMessage:"Block entire domain"}}),N=Object(b.g)(Object(m.connect)((function(){return function(){return{}}}),(function(n,o){var a=o.intl;return{onBlockDomain:function(o){n(Object(R.d)("CONFIRM",{message:Object(c.a)(b.b,{id:"confirmations.domain_block.message",defaultMessage:"Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",values:{domain:Object(c.a)("strong",{},void 0,o)}}),confirm:a.formatMessage(q.blockDomainConfirm),onConfirm:function(){return n(Object(M.e)(o))}}))},onUnblockDomain:function(o){n(Object(M.h)(o))}}}))(C)),T=a(1049);var I=Object(b.f)({heading:{id:"column.domain_blocks",defaultMessage:"Blocked domains"},unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unblock domain {domain}"}}),S=Object(m.connect)((function(n){return{domains:n.getIn(["domain_lists","blocks","items"]),hasMore:!!n.getIn(["domain_lists","blocks","next"])}}))(_=Object(b.g)((w=D=function(n){Object(s.a)(a,n);var o;o=a;function a(){for(var o,a=arguments.length,e=new Array(a),t=0;t<a;t++)e[t]=arguments[t];return o=n.call.apply(n,[this].concat(e))||this,Object(d.a)(Object(r.a)(o),"handleLoadMore",u()((function(){o.props.dispatch(Object(M.f)())}),300,{leading:!0})),o}var e=a.prototype;return e.componentWillMount=function(){this.props.dispatch(Object(M.g)())},e.render=function(){var n=this.props,o=n.intl,a=n.domains,e=n.shouldUpdateScroll,t=n.hasMore,i=n.multiColumn;if(!a)return Object(c.a)(g.a,{},void 0,Object(c.a)(k.a,{}));var r=Object(c.a)(b.b,{id:"empty_column.domain_blocks",defaultMessage:"There are no blocked domains yet."});return(Object(c.a)(g.a,{bindToDocument:!i,icon:"minus-circle",heading:o.formatMessage(I.heading)},void 0,Object(c.a)(v.a,{}),Object(c.a)(T.a,{scrollKey:"domain_blocks",onLoadMore:this.handleLoadMore,hasMore:t,shouldUpdateScroll:e,emptyMessage:r,bindToDocument:!i},void 0,a.map((function(n){return Object(c.a)(N,{domain:n},n)})))))},a}(f.a),Object(d.a)(D,"propTypes",{params:j.a.object.isRequired,dispatch:j.a.func.isRequired,shouldUpdateScroll:j.a.func,hasMore:j.a.bool,domains:h.a.orderedSet,intl:j.a.object.isRequired,multiColumn:j.a.bool}),_=w))||_)||_}}]);
//# sourceMappingURL=domain_blocks.js.map

+ 1
- 1
priv/static/packs/features/domain_blocks.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/favourited_statuses.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{799:function(t,e,a){"use strict";a.r(e),a.d(e,"default",(function(){return C}));var o,n,s,i=a(0),c=a(2),u=a(7),l=a(1),r=a(62),d=a.n(r),h=a(3),p=a.n(h),b=a(13),f=a(5),j=a.n(f),O=a(14),m=a.n(O),g=a(204),v=a(731),M=a(733),I=a(250),w=a(1038),y=a(6),L=a(18),k=Object(y.f)({heading:{id:"column.favourites",defaultMessage:"Favourites"}}),C=Object(b.connect)((function(t){return{statusIds:t.getIn(["status_lists","favourites","items"]),isLoading:t.getIn(["status_lists","favourites","isLoading"],!0),hasMore:!!t.getIn(["status_lists","favourites","next"])}}))(o=Object(y.g)((s=n=function(t){function e(){for(var e,a=arguments.length,o=new Array(a),n=0;n<a;n++)o[n]=arguments[n];return e=t.call.apply(t,[this].concat(o))||this,Object(l.a)(Object(c.a)(e),"handlePin",(function(){var t=e.props,a=t.columnId,o=t.dispatch;o(a?Object(I.h)(a):Object(I.e)("FAVOURITES",{}))})),Object(l.a)(Object(c.a)(e),"handleMove",(function(t){var a=e.props,o=a.columnId;(0,a.dispatch)(Object(I.g)(o,t))})),Object(l.a)(Object(c.a)(e),"handleHeaderClick",(function(){e.column.scrollTop()})),Object(l.a)(Object(c.a)(e),"setRef",(function(t){e.column=t})),Object(l.a)(Object(c.a)(e),"handleLoadMore",d()((function(){e.props.dispatch(Object(g.g)())}),300,{leading:!0})),e}Object(u.a)(e,t);var a=e.prototype;return a.componentWillMount=function(){this.props.dispatch(Object(g.h)())},a.render=function(){var t=this.props,e=t.intl,a=t.shouldUpdateScroll,o=t.statusIds,n=t.columnId,s=t.multiColumn,c=t.hasMore,u=t.isLoading,l=!!n,r=Object(i.a)(y.b,{id:"empty_column.favourited_statuses",defaultMessage:"You don't have any favourite toots yet. When you favourite one, it will show up here."});return p.a.createElement(v.a,{bindToDocument:!s,ref:this.setRef,label:e.formatMessage(k.heading)},Object(i.a)(M.a,{icon:"star",title:e.formatMessage(k.heading),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:l,multiColumn:s,showBackButton:!0}),Object(i.a)(w.a,{trackScroll:!l,statusIds:o,scrollKey:"favourited_statuses-"+n,hasMore:c,isLoading:u,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:r,bindToDocument:!s}))},e}(L.a),Object(l.a)(n,"propTypes",{dispatch:j.a.func.isRequired,shouldUpdateScroll:j.a.func,statusIds:m.a.list.isRequired,intl:j.a.object.isRequired,columnId:j.a.string,multiColumn:j.a.bool,hasMore:j.a.bool,isLoading:j.a.bool}),o=s))||o)||o}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{825:function(t,e,a){"use strict";a.r(e),a.d(e,"default",(function(){return C}));var o,n,s,i=a(0),c=a(2),u=(a(9),a(6),a(8)),r=a(1),l=a(65),d=a.n(l),h=a(3),p=a.n(h),b=a(15),f=a(5),j=a.n(f),O=a(16),m=a.n(O),g=a(208),v=a(757),M=a(759),I=a(253),w=a(1065),y=a(7),L=a(21);var k=Object(y.f)({heading:{id:"column.favourites",defaultMessage:"Favourites"}}),C=Object(b.connect)((function(t){return{statusIds:t.getIn(["status_lists","favourites","items"]),isLoading:t.getIn(["status_lists","favourites","isLoading"],!0),hasMore:!!t.getIn(["status_lists","favourites","next"])}}))(o=Object(y.g)((s=n=function(t){Object(u.a)(a,t);var e;e=a;function a(){for(var e,a=arguments.length,o=new Array(a),n=0;n<a;n++)o[n]=arguments[n];return e=t.call.apply(t,[this].concat(o))||this,Object(r.a)(Object(c.a)(e),"handlePin",(function(){var t=e.props,a=t.columnId,o=t.dispatch;o(a?Object(I.h)(a):Object(I.e)("FAVOURITES",{}))})),Object(r.a)(Object(c.a)(e),"handleMove",(function(t){var a=e.props,o=a.columnId;(0,a.dispatch)(Object(I.g)(o,t))})),Object(r.a)(Object(c.a)(e),"handleHeaderClick",(function(){e.column.scrollTop()})),Object(r.a)(Object(c.a)(e),"setRef",(function(t){e.column=t})),Object(r.a)(Object(c.a)(e),"handleLoadMore",d()((function(){e.props.dispatch(Object(g.g)())}),300,{leading:!0})),e}var o=a.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(g.h)())},o.render=function(){var t=this.props,e=t.intl,a=t.shouldUpdateScroll,o=t.statusIds,n=t.columnId,s=t.multiColumn,c=t.hasMore,u=t.isLoading,r=!!n,l=Object(i.a)(y.b,{id:"empty_column.favourited_statuses",defaultMessage:"You don't have any favourite toots yet. When you favourite one, it will show up here."});return p.a.createElement(v.a,{bindToDocument:!s,ref:this.setRef,label:e.formatMessage(k.heading)},Object(i.a)(M.a,{icon:"star",title:e.formatMessage(k.heading),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:r,multiColumn:s,showBackButton:!0}),Object(i.a)(w.a,{trackScroll:!r,statusIds:o,scrollKey:"favourited_statuses-"+n,hasMore:c,isLoading:u,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:l,bindToDocument:!s}))},a}(L.a),Object(r.a)(n,"propTypes",{dispatch:j.a.func.isRequired,shouldUpdateScroll:j.a.func,statusIds:m.a.list.isRequired,intl:j.a.object.isRequired,columnId:j.a.string,multiColumn:j.a.bool,hasMore:j.a.bool,isLoading:j.a.bool}),o=s))||o)||o}}]);
//# sourceMappingURL=favourited_statuses.js.map

+ 1
- 1
priv/static/packs/features/favourited_statuses.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/favourites.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{797:function(t,e,a){"use strict";a.r(e),a.d(e,"default",(function(){return q}));var s,o,r,n=a(0),c=a(2),i=a(7),u=a(1),p=(a(3),a(13)),d=a(18),l=a(5),h=a.n(l),f=a(14),b=a.n(f),m=a(300),j=a(45),O=a(6),v=a(1026),I=a(731),w=a(1023),y=a(26),g=a(733),R=Object(O.f)({refresh:{id:"refresh",defaultMessage:"Refresh"}}),q=Object(p.connect)((function(t,e){return{accountIds:t.getIn(["user_lists","favourited_by",e.params.statusId])}}))(s=Object(O.g)((r=o=function(t){function e(){for(var e,a=arguments.length,s=new Array(a),o=0;o<a;o++)s[o]=arguments[o];return e=t.call.apply(t,[this].concat(s))||this,Object(u.a)(Object(c.a)(e),"handleRefresh",(function(){e.props.dispatch(Object(j.q)(e.props.params.statusId))})),e}Object(i.a)(e,t);var a=e.prototype;return a.componentWillMount=function(){this.props.accountIds||this.props.dispatch(Object(j.q)(this.props.params.statusId))},a.componentWillReceiveProps=function(t){t.params.statusId!==this.props.params.statusId&&t.params.statusId&&this.props.dispatch(Object(j.q)(t.params.statusId))},a.render=function(){var t=this.props,e=t.intl,a=t.shouldUpdateScroll,s=t.accountIds,o=t.multiColumn;if(!s)return Object(n.a)(I.a,{},void 0,Object(n.a)(m.a,{}));var r=Object(n.a)(O.b,{id:"empty_column.favourites",defaultMessage:"No one has favourited this toot yet. When someone does, they will show up here."});return Object(n.a)(I.a,{bindToDocument:!o},void 0,Object(n.a)(g.a,{showBackButton:!0,multiColumn:o,extraButton:Object(n.a)("button",{className:"column-header__button",title:e.formatMessage(R.refresh),"aria-label":e.formatMessage(R.refresh),onClick:this.handleRefresh},void 0,Object(n.a)(y.a,{id:"refresh"}))}),Object(n.a)(w.a,{scrollKey:"favourites",shouldUpdateScroll:a,emptyMessage:r,bindToDocument:!o},void 0,s.map((function(t){return Object(n.a)(v.a,{id:t,withNote:!1},t)}))))},e}(d.a),Object(u.a)(o,"propTypes",{params:h.a.object.isRequired,dispatch:h.a.func.isRequired,shouldUpdateScroll:h.a.func,accountIds:b.a.list,multiColumn:h.a.bool,intl:h.a.object.isRequired}),s=r))||s)||s}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{823:function(t,e,a){"use strict";a.r(e),a.d(e,"default",(function(){return q}));var s,o,r,n=a(0),c=a(2),i=(a(9),a(6),a(8)),u=a(1),p=(a(3),a(15)),d=a(21),l=a(5),h=a.n(l),f=a(16),b=a.n(f),m=a(306),j=a(46),O=a(7),v=a(1053),I=a(757),w=a(1049),y=a(27),g=a(759);var R=Object(O.f)({refresh:{id:"refresh",defaultMessage:"Refresh"}}),q=Object(p.connect)((function(t,e){return{accountIds:t.getIn(["user_lists","favourited_by",e.params.statusId])}}))(s=Object(O.g)((r=o=function(t){Object(i.a)(a,t);var e;e=a;function a(){for(var e,a=arguments.length,s=new Array(a),o=0;o<a;o++)s[o]=arguments[o];return e=t.call.apply(t,[this].concat(s))||this,Object(u.a)(Object(c.a)(e),"handleRefresh",(function(){e.props.dispatch(Object(j.q)(e.props.params.statusId))})),e}var s=a.prototype;return s.componentWillMount=function(){this.props.accountIds||this.props.dispatch(Object(j.q)(this.props.params.statusId))},s.componentWillReceiveProps=function(t){t.params.statusId!==this.props.params.statusId&&t.params.statusId&&this.props.dispatch(Object(j.q)(t.params.statusId))},s.render=function(){var t=this.props,e=t.intl,a=t.shouldUpdateScroll,s=t.accountIds,o=t.multiColumn;if(!s)return Object(n.a)(I.a,{},void 0,Object(n.a)(m.a,{}));var r=Object(n.a)(O.b,{id:"empty_column.favourites",defaultMessage:"No one has favourited this toot yet. When someone does, they will show up here."});return(Object(n.a)(I.a,{bindToDocument:!o},void 0,Object(n.a)(g.a,{showBackButton:!0,multiColumn:o,extraButton:Object(n.a)("button",{className:"column-header__button",title:e.formatMessage(R.refresh),"aria-label":e.formatMessage(R.refresh),onClick:this.handleRefresh},void 0,Object(n.a)(y.a,{id:"refresh"}))}),Object(n.a)(w.a,{scrollKey:"favourites",shouldUpdateScroll:a,emptyMessage:r,bindToDocument:!o},void 0,s.map((function(t){return Object(n.a)(v.a,{id:t,withNote:!1},t)})))))},a}(d.a),Object(u.a)(o,"propTypes",{params:h.a.object.isRequired,dispatch:h.a.func.isRequired,shouldUpdateScroll:h.a.func,accountIds:b.a.list,multiColumn:h.a.bool,intl:h.a.object.isRequired}),s=r))||s)||s}}]);
//# sourceMappingURL=favourites.js.map

+ 1
- 1
priv/static/packs/features/favourites.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/follow_requests.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{825:function(e,t,a){"use strict";a.r(t);var o,c,n,i,r,s,u=a(0),l=a(2),d=a(7),b=a(1),j=a(62),p=a.n(j),f=(a(3),a(13)),h=a(6),O=a(18),m=a(5),v=a.n(m),_=a(14),g=a.n(_),w=a(300),M=a(731),q=a(737),y=a(206),z=a(294),R=a(111),N=a(118),I=a(50),k=Object(h.f)({authorize:{id:"follow_request.authorize",defaultMessage:"Authorize"},reject:{id:"follow_request.reject",defaultMessage:"Reject"}}),A=Object(h.g)((n=c=function(e){function t(){return e.apply(this,arguments)||this}return Object(d.a)(t,e),t.prototype.render=function(){var e=this.props,t=e.intl,a=e.account,o=e.onAuthorize,c=e.onReject,n={__html:a.get("note_emojified")};return Object(u.a)("div",{className:"account-authorize__wrapper"},void 0,Object(u.a)("div",{className:"account-authorize"},void 0,Object(u.a)(z.a,{href:a.get("url"),to:"/accounts/"+a.get("id"),className:"detailed-status__display-name"},void 0,Object(u.a)("div",{className:"account-authorize__avatar"},void 0,Object(u.a)(R.a,{account:a,size:48})),Object(u.a)(N.a,{account:a})),Object(u.a)("div",{className:"account__header__content",dangerouslySetInnerHTML:n})),Object(u.a)("div",{className:"account--panel"},void 0,Object(u.a)("div",{className:"account--panel__button"},void 0,Object(u.a)(I.a,{title:t.formatMessage(k.authorize),icon:"check",onClick:o})),Object(u.a)("div",{className:"account--panel__button"},void 0,Object(u.a)(I.a,{title:t.formatMessage(k.reject),icon:"times",onClick:c}))))},t}(O.a),Object(b.a)(c,"propTypes",{account:g.a.map.isRequired,onAuthorize:v.a.func.isRequired,onReject:v.a.func.isRequired,intl:v.a.object.isRequired}),o=n))||o,T=a(25),C=Object(f.connect)((function(){var e=Object(y.d)();return function(t,a){return{account:e(t,a.id)}}}),(function(e,t){var a=t.id;return{onAuthorize:function(){e(Object(T.v)(a))},onReject:function(){e(Object(T.I)(a))}}}))(A),L=a(1023);a.d(t,"default",(function(){return U}));var S=Object(h.f)({heading:{id:"column.follow_requests",defaultMessage:"Follow requests"}}),U=Object(f.connect)((function(e){return{accountIds:e.getIn(["user_lists","follow_requests","items"]),hasMore:!!e.getIn(["user_lists","follow_requests","next"])}}))(i=Object(h.g)((s=r=function(e){function t(){for(var t,a=arguments.length,o=new Array(a),c=0;c<a;c++)o[c]=arguments[c];return t=e.call.apply(e,[this].concat(o))||this,Object(b.a)(Object(l.a)(t),"handleLoadMore",p()((function(){t.props.dispatch(Object(T.x)())}),300,{leading:!0})),t}Object(d.a)(t,e);var a=t.prototype;return a.componentWillMount=function(){this.props.dispatch(Object(T.B)())},a.render=function(){var e=this.props,t=e.intl,a=e.shouldUpdateScroll,o=e.accountIds,c=e.hasMore,n=e.multiColumn;if(!o)return Object(u.a)(M.a,{},void 0,Object(u.a)(w.a,{}));var i=Object(u.a)(h.b,{id:"empty_column.follow_requests",defaultMessage:"You don't have any follow requests yet. When you receive one, it will show up here."});return Object(u.a)(M.a,{bindToDocument:!n,icon:"user-plus",heading:t.formatMessage(S.heading)},void 0,Object(u.a)(q.a,{}),Object(u.a)(L.a,{scrollKey:"follow_requests",onLoadMore:this.handleLoadMore,hasMore:c,shouldUpdateScroll:a,emptyMessage:i,bindToDocument:!n},void 0,o.map((function(e){return Object(u.a)(C,{id:e},e)}))))},t}(O.a),Object(b.a)(r,"propTypes",{params:v.a.object.isRequired,dispatch:v.a.func.isRequired,shouldUpdateScroll:v.a.func,hasMore:v.a.bool,accountIds:g.a.list,intl:v.a.object.isRequired,multiColumn:v.a.bool}),i=s))||i)||i}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{851:function(e,t,a){"use strict";a.r(t),a.d(t,"default",(function(){return U}));var o,n,c,i=a(0),s=a(2),u=(a(9),a(6),a(8)),r=a(1),l=a(65),d=a.n(l),b=(a(3),a(15)),p=a(7),f=a(21),h=a(5),j=a.n(h),m=a(16),v=a.n(m),O=a(306),_=a(757),g=a(763),w=a(210),q=a(300),y=a(115),M=a(122),k=a(53);var z,R,I,N=Object(p.f)({authorize:{id:"follow_request.authorize",defaultMessage:"Authorize"},reject:{id:"follow_request.reject",defaultMessage:"Reject"}}),A=Object(p.g)((c=n=function(e){Object(u.a)(a,e);var t;t=a;function a(){return e.apply(this,arguments)||this}return a.prototype.render=function(){var e=this.props,t=e.intl,a=e.account,o=e.onAuthorize,n=e.onReject,c={__html:a.get("note_emojified")};return Object(i.a)("div",{className:"account-authorize__wrapper"},void 0,Object(i.a)("div",{className:"account-authorize"},void 0,Object(i.a)(q.a,{href:a.get("url"),to:"/accounts/"+a.get("id"),className:"detailed-status__display-name"},void 0,Object(i.a)("div",{className:"account-authorize__avatar"},void 0,Object(i.a)(y.a,{account:a,size:48})),Object(i.a)(M.a,{account:a})),Object(i.a)("div",{className:"account__header__content",dangerouslySetInnerHTML:c})),Object(i.a)("div",{className:"account--panel"},void 0,Object(i.a)("div",{className:"account--panel__button"},void 0,Object(i.a)(k.a,{title:t.formatMessage(N.authorize),icon:"check",onClick:o})),Object(i.a)("div",{className:"account--panel__button"},void 0,Object(i.a)(k.a,{title:t.formatMessage(N.reject),icon:"times",onClick:n}))))},a}(f.a),Object(r.a)(n,"propTypes",{account:v.a.map.isRequired,onAuthorize:j.a.func.isRequired,onReject:j.a.func.isRequired,intl:j.a.object.isRequired}),o=c))||o,T=a(26),x=Object(b.connect)((function(){var e=Object(w.d)();return function(t,a){return{account:e(t,a.id)}}}),(function(e,t){var a=t.id;return{onAuthorize:function(){e(Object(T.v)(a))},onReject:function(){e(Object(T.I)(a))}}}))(A),C=a(1049),L=a(22);var S=Object(p.f)({heading:{id:"column.follow_requests",defaultMessage:"Follow requests"}}),U=Object(b.connect)((function(e){return{accountIds:e.getIn(["user_lists","follow_requests","items"]),hasMore:!!e.getIn(["user_lists","follow_requests","next"]),locked:!!e.getIn(["accounts",L.n,"locked"]),domain:e.getIn(["meta","domain"])}}))(z=Object(p.g)((I=R=function(e){Object(u.a)(a,e);var t;t=a;function a(){for(var t,a=arguments.length,o=new Array(a),n=0;n<a;n++)o[n]=arguments[n];return t=e.call.apply(e,[this].concat(o))||this,Object(r.a)(Object(s.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(T.x)())}),300,{leading:!0})),t}var o=a.prototype;return o.componentWillMount=function(){this.props.dispatch(Object(T.B)())},o.render=function(){var e=this.props,t=e.intl,a=e.shouldUpdateScroll,o=e.accountIds,n=e.hasMore,c=e.multiColumn,s=e.locked,u=e.domain;if(!o)return Object(i.a)(_.a,{},void 0,Object(i.a)(O.a,{}));var r=Object(i.a)(p.b,{id:"empty_column.follow_requests",defaultMessage:"You don't have any follow requests yet. When you receive one, it will show up here."}),l=s?null:Object(i.a)("div",{className:"follow_requests-unlocked_explanation"},void 0,Object(i.a)(p.b,{id:"follow_requests.unlocked_explanation",defaultMessage:"Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.",values:{domain:u}}));return Object(i.a)(_.a,{bindToDocument:!c,icon:"user-plus",heading:t.formatMessage(S.heading)},void 0,Object(i.a)(g.a,{}),Object(i.a)(C.a,{scrollKey:"follow_requests",onLoadMore:this.handleLoadMore,hasMore:n,shouldUpdateScroll:a,emptyMessage:r,bindToDocument:!c,prepend:l},void 0,o.map((function(e){return Object(i.a)(x,{id:e},e)}))))},a}(f.a),Object(r.a)(R,"propTypes",{params:j.a.object.isRequired,dispatch:j.a.func.isRequired,shouldUpdateScroll:j.a.func,hasMore:j.a.bool,accountIds:v.a.list,locked:j.a.bool,domain:j.a.string,intl:j.a.object.isRequired,multiColumn:j.a.bool}),z=I))||z)||z}}]);
//# sourceMappingURL=follow_requests.js.map

+ 1
- 1
priv/static/packs/features/follow_requests.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/followers.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{794:function(a,t,o){"use strict";o.r(t),o.d(t,"default",(function(){return C}));var c,e,s,n=o(0),r=o(2),p=o(7),i=o(1),u=o(62),d=o.n(u),l=(o(3),o(13)),b=o(18),h=o(5),m=o.n(h),f=o(14),j=o.n(f),I=o(300),O=o(25),y=o(6),w=o(1026),v=o(731),M=o(1057),g=o(738),k=o(1023),A=o(1030),C=Object(l.connect)((function(a,t){return{isAccount:!!a.getIn(["accounts",t.params.accountId]),accountIds:a.getIn(["user_lists","followers",t.params.accountId,"items"]),hasMore:!!a.getIn(["user_lists","followers",t.params.accountId,"next"]),blockedBy:a.getIn(["relationships",t.params.accountId,"blocked_by"],!1)}}))((s=e=function(a){function t(){for(var t,o=arguments.length,c=new Array(o),e=0;e<o;e++)c[e]=arguments[e];return t=a.call.apply(a,[this].concat(c))||this,Object(i.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(O.y)(t.props.params.accountId))}),300,{leading:!0})),t}Object(p.a)(t,a);var o=t.prototype;return o.componentWillMount=function(){this.props.accountIds||(this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.C)(this.props.params.accountId)))},o.componentWillReceiveProps=function(a){a.params.accountId!==this.props.params.accountId&&a.params.accountId&&(this.props.dispatch(Object(O.A)(a.params.accountId)),this.props.dispatch(Object(O.C)(a.params.accountId)))},o.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy,s=a.isAccount,r=a.multiColumn;if(!s)return Object(n.a)(v.a,{},void 0,Object(n.a)(A.a,{}));if(!o)return Object(n.a)(v.a,{},void 0,Object(n.a)(I.a,{}));var p=e?Object(n.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(n.a)(y.b,{id:"account.followers.empty",defaultMessage:"No one follows this user yet."});return Object(n.a)(v.a,{},void 0,Object(n.a)(g.a,{multiColumn:r}),Object(n.a)(k.a,{scrollKey:"followers",hasMore:c,onLoadMore:this.handleLoadMore,shouldUpdateScroll:t,prepend:Object(n.a)(M.a,{accountId:this.props.params.accountId,hideTabs:!0}),alwaysPrepend:!0,emptyMessage:p,bindToDocument:!r},void 0,e?[]:o.map((function(a){return Object(n.a)(w.a,{id:a,withNote:!1},a)}))))},t}(b.a),Object(i.a)(e,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,blockedBy:m.a.bool,isAccount:m.a.bool,multiColumn:m.a.bool}),c=s))||c}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{820:function(a,t,o){"use strict";o.r(t),o.d(t,"default",(function(){return C}));var c,e,s,n=o(0),r=o(2),p=(o(9),o(6),o(8)),i=o(1),u=o(65),d=o.n(u),l=(o(3),o(15)),b=o(21),h=o(5),m=o.n(h),f=o(16),j=o.n(f),I=o(306),O=o(26),y=o(7),v=o(1053),w=o(757),M=o(1084),g=o(764),k=o(1049),A=o(1057);var C=Object(l.connect)((function(a,t){return{isAccount:!!a.getIn(["accounts",t.params.accountId]),accountIds:a.getIn(["user_lists","followers",t.params.accountId,"items"]),hasMore:!!a.getIn(["user_lists","followers",t.params.accountId,"next"]),blockedBy:a.getIn(["relationships",t.params.accountId,"blocked_by"],!1)}}))((s=e=function(a){Object(p.a)(o,a);var t;t=o;function o(){for(var t,o=arguments.length,c=new Array(o),e=0;e<o;e++)c[e]=arguments[e];return t=a.call.apply(a,[this].concat(c))||this,Object(i.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(O.y)(t.props.params.accountId))}),300,{leading:!0})),t}var c=o.prototype;return c.componentWillMount=function(){this.props.accountIds||(this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.C)(this.props.params.accountId)))},c.componentWillReceiveProps=function(a){a.params.accountId!==this.props.params.accountId&&a.params.accountId&&(this.props.dispatch(Object(O.A)(a.params.accountId)),this.props.dispatch(Object(O.C)(a.params.accountId)))},c.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy,s=a.isAccount,r=a.multiColumn;if(!s)return Object(n.a)(w.a,{},void 0,Object(n.a)(A.a,{}));if(!o)return Object(n.a)(w.a,{},void 0,Object(n.a)(I.a,{}));var p=e?Object(n.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(n.a)(y.b,{id:"account.followers.empty",defaultMessage:"No one follows this user yet."});return(Object(n.a)(w.a,{},void 0,Object(n.a)(g.a,{multiColumn:r}),Object(n.a)(k.a,{scrollKey:"followers",hasMore:c,onLoadMore:this.handleLoadMore,shouldUpdateScroll:t,prepend:Object(n.a)(M.a,{accountId:this.props.params.accountId,hideTabs:!0}),alwaysPrepend:!0,emptyMessage:p,bindToDocument:!r},void 0,e?[]:o.map((function(a){return Object(n.a)(v.a,{id:a,withNote:!1},a)})))))},o}(b.a),Object(i.a)(e,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,blockedBy:m.a.bool,isAccount:m.a.bool,multiColumn:m.a.bool}),c=s))||c}}]);
//# sourceMappingURL=followers.js.map

+ 1
- 1
priv/static/packs/features/followers.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/following.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{795:function(a,t,o){"use strict";o.r(t),o.d(t,"default",(function(){return _}));var c,e,n,s=o(0),r=o(2),i=o(7),p=o(1),u=o(62),d=o.n(u),l=(o(3),o(13)),b=o(18),h=o(5),m=o.n(h),f=o(14),j=o.n(f),I=o(300),O=o(25),y=o(6),w=o(1026),g=o(731),v=o(1057),M=o(738),k=o(1023),A=o(1030),_=Object(l.connect)((function(a,t){return{isAccount:!!a.getIn(["accounts",t.params.accountId]),accountIds:a.getIn(["user_lists","following",t.params.accountId,"items"]),hasMore:!!a.getIn(["user_lists","following",t.params.accountId,"next"]),blockedBy:a.getIn(["relationships",t.params.accountId,"blocked_by"],!1)}}))((n=e=function(a){function t(){for(var t,o=arguments.length,c=new Array(o),e=0;e<o;e++)c[e]=arguments[e];return t=a.call.apply(a,[this].concat(c))||this,Object(p.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(O.z)(t.props.params.accountId))}),300,{leading:!0})),t}Object(i.a)(t,a);var o=t.prototype;return o.componentWillMount=function(){this.props.accountIds||(this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.D)(this.props.params.accountId)))},o.componentWillReceiveProps=function(a){a.params.accountId!==this.props.params.accountId&&a.params.accountId&&(this.props.dispatch(Object(O.A)(a.params.accountId)),this.props.dispatch(Object(O.D)(a.params.accountId)))},o.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy,n=a.isAccount,r=a.multiColumn;if(!n)return Object(s.a)(g.a,{},void 0,Object(s.a)(A.a,{}));if(!o)return Object(s.a)(g.a,{},void 0,Object(s.a)(I.a,{}));var i=e?Object(s.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(s.a)(y.b,{id:"account.follows.empty",defaultMessage:"This user doesn't follow anyone yet."});return Object(s.a)(g.a,{},void 0,Object(s.a)(M.a,{multiColumn:r}),Object(s.a)(k.a,{scrollKey:"following",hasMore:c,onLoadMore:this.handleLoadMore,shouldUpdateScroll:t,prepend:Object(s.a)(v.a,{accountId:this.props.params.accountId,hideTabs:!0}),alwaysPrepend:!0,emptyMessage:i,bindToDocument:!r},void 0,e?[]:o.map((function(a){return Object(s.a)(w.a,{id:a,withNote:!1},a)}))))},t}(b.a),Object(p.a)(e,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,blockedBy:m.a.bool,isAccount:m.a.bool,multiColumn:m.a.bool}),c=n))||c}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{821:function(a,t,o){"use strict";o.r(t),o.d(t,"default",(function(){return _}));var c,e,n,s=o(0),r=o(2),i=(o(9),o(6),o(8)),p=o(1),u=o(65),d=o.n(u),l=(o(3),o(15)),b=o(21),h=o(5),m=o.n(h),f=o(16),j=o.n(f),I=o(306),O=o(26),y=o(7),v=o(1053),w=o(757),g=o(1084),M=o(764),k=o(1049),A=o(1057);var _=Object(l.connect)((function(a,t){return{isAccount:!!a.getIn(["accounts",t.params.accountId]),accountIds:a.getIn(["user_lists","following",t.params.accountId,"items"]),hasMore:!!a.getIn(["user_lists","following",t.params.accountId,"next"]),blockedBy:a.getIn(["relationships",t.params.accountId,"blocked_by"],!1)}}))((n=e=function(a){Object(i.a)(o,a);var t;t=o;function o(){for(var t,o=arguments.length,c=new Array(o),e=0;e<o;e++)c[e]=arguments[e];return t=a.call.apply(a,[this].concat(c))||this,Object(p.a)(Object(r.a)(t),"handleLoadMore",d()((function(){t.props.dispatch(Object(O.z)(t.props.params.accountId))}),300,{leading:!0})),t}var c=o.prototype;return c.componentWillMount=function(){this.props.accountIds||(this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.D)(this.props.params.accountId)))},c.componentWillReceiveProps=function(a){a.params.accountId!==this.props.params.accountId&&a.params.accountId&&(this.props.dispatch(Object(O.A)(a.params.accountId)),this.props.dispatch(Object(O.D)(a.params.accountId)))},c.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy,n=a.isAccount,r=a.multiColumn;if(!n)return Object(s.a)(w.a,{},void 0,Object(s.a)(A.a,{}));if(!o)return Object(s.a)(w.a,{},void 0,Object(s.a)(I.a,{}));var i=e?Object(s.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(s.a)(y.b,{id:"account.follows.empty",defaultMessage:"This user doesn't follow anyone yet."});return(Object(s.a)(w.a,{},void 0,Object(s.a)(M.a,{multiColumn:r}),Object(s.a)(k.a,{scrollKey:"following",hasMore:c,onLoadMore:this.handleLoadMore,shouldUpdateScroll:t,prepend:Object(s.a)(g.a,{accountId:this.props.params.accountId,hideTabs:!0}),alwaysPrepend:!0,emptyMessage:i,bindToDocument:!r},void 0,e?[]:o.map((function(a){return Object(s.a)(v.a,{id:a,withNote:!1},a)})))))},o}(b.a),Object(p.a)(e,"propTypes",{params:m.a.object.isRequired,dispatch:m.a.func.isRequired,shouldUpdateScroll:m.a.func,accountIds:j.a.list,hasMore:m.a.bool,blockedBy:m.a.bool,isAccount:m.a.bool,multiColumn:m.a.bool}),c=n))||c}}]);
//# sourceMappingURL=following.js.map

+ 1
- 1
priv/static/packs/features/following.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/generic_not_found.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{798:function(a,n,e){"use strict";e.r(n);var t=e(0),c=(e(3),e(731)),o=e(1030);n.default=function(){return Object(t.a)(c.a,{},void 0,Object(t.a)(o.a,{fullPage:!0}))}}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{824:function(a,n,e){"use strict";e.r(n);var t=e(0),c=(e(3),e(757)),o=e(1057);n.default=function(){return Object(t.a)(c.a,{},void 0,Object(t.a)(o.a,{fullPage:!0}))}}}]);
//# sourceMappingURL=generic_not_found.js.map

+ 1
- 1
priv/static/packs/features/getting_started.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/getting_started.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/glitch/async/directory.js
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/glitch/async/directory.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
priv/static/packs/features/glitch/async/list_adder.js View File

@@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{821:function(t,e,n){"use strict";n.r(e);var i,a,c,o,s,r,d,u,l,p=n(0),b=n(7),f=n(1),v=(n(3),n(5)),j=n.n(v),O=n(14),m=n.n(O),_=n(13),R=n(18),g=n(6),I=n(28),h=n(54),N=n(39),q=n(23),y=Object(g.f)({remove:{id:"lists.account.remove",defaultMessage:"Remove from list"},add:{id:"lists.account.add",defaultMessage:"Add to list"}}),w=Object(_.connect)((function(t,e){var n=e.listId,i=e.added;return{list:t.get("lists").get(n),added:void 0===i?t.getIn(["listAdder","lists","items"]).includes(n):i}}),(function(t,e){var n=e.listId;return{onRemove:function(){return t(Object(I.J)(n))},onAdd:function(){return t(Object(I.A)(n))}}}))(i=Object(g.g)((c=a=function(t){function e(){return t.apply(this,arguments)||this}return Object(b.a)(e,t),e.prototype.render=function(){var t,e=this.props,n=e.list,i=e.intl,a=e.onRemove,c=e.onAdd;return t=e.added?Object(p.a)(N.a,{icon:"times",title:i.formatMessage(y.remove),onClick:a}):Object(p.a)(N.a,{icon:"plus",title:i.formatMessage(y.add),onClick:c}),Object(p.a)("div",{className:"list"},void 0,Object(p.a)("div",{className:"list__wrapper"},void 0,Object(p.a)("div",{className:"list__display-name"},void 0,Object(p.a)(q.a,{id:"list-ul",className:"column-link__icon",fixedWidth:!0}),n.get("title")),Object(p.a)("div",{className:"account__relationship"},void 0,t)))},e}(R.a),Object(f.a)(a,"propTypes",{list:m.a.map.isRequired,intl:j.a.object.isRequired,onRemove:j.a.func.isRequired,onAdd:j.a.func.isRequired,added:j.a.bool}),Object(f.a)(a,"defaultProps",{added:!1}),i=c))||i)||i,A=n(103),k=n(91),M=n(93),z=Object(_.connect)((function(){var t=Object(A.d)();return function(e,n){var i=n.accountId;return{account:t(e,i)}}}))(o=Object(g.g)((r=s=function(t){function e(){return t.apply(this,arguments)||this}return Object(b.a)(e,t),e.prototype.render=function(){var t=this.props.account;return Object(p.a)("div",{className:"account"},void 0,Object(p.a)("div",{className:"account__wrapper"},void 0,Object(p.a)("div",{className:"account__display-name"},void 0,Object(p.a)("div",{className:"account__avatar-wrapper"},void 0,Object(p.a)(k.a,{account:t,size:36})),Object(p.a)(M.a,{account:t}))))},e}(R.a),Object(f.a)(s,"propTypes",{account:m.a.map.isRequired}),o=r))||o)||o,C=n(1118);n.d(e,"default",(function(){return T}));var J=Object(h.a)([function(t){return t.get("lists")}],(function(t){return t?t.toList().filter((function(t){return!!t})).sort((function(t,e){return t.get("title").localeCompare(e.get("title"))})):t})),T=Object(_.connect)((function(t){return{listIds:J(t).map((function(t){return t.get("id")}))}}),(function(t){return{onInitialize:function(e){return t(Object(I.N)(e))},onReset:function(){return t(Object(I.L)())}}}))(d=Object(g.g)((l=u=function(t){function e(){return t.apply(this,arguments)||this}Object(b.a)(e,t);var n=e.prototype;return n.componentDidMount=function(){var t=this.props;(0,t.onInitialize)(t.accountId)},n.componentWillUnmount=function(){(0,this.props.onReset)()},n.render=function(){var t=this.props,e=t.accountId,n=t.listIds;return Object(p.a)("div",{className:"modal-root__modal list-adder"},void 0,Object(p.a)("div",{className:"list-adder__account"},void 0,Object(p.a)(z,{accountId:e})),Object(p.a)(C.a,{}),Object(p.a)("div",{className:"list-adder__lists"},void 0,n.map((function(t){return Object(p.a)(w,{listId:t},t)}))))},e}(R.a),Object(f.a)(u,"propTypes",{accountId:j.a.string.isRequired,onClose:j.a.func.isRequired,intl:j.a.object.isRequired,onInitialize:j.a.func.isRequired,onReset:j.a.func.isRequired,listIds:m.a.list.isRequired}),d=l))||d)||d}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{848:function(t,e,n){"use strict";n.r(e),n.d(e,"default",(function(){return T}));var i,a,c,o=n(0),r=(n(9),n(6),n(8)),s=n(1),d=(n(3),n(5)),u=n.n(d),l=n(16),p=n.n(l),v=n(15),b=n(21),f=n(7),j=n(30),O=n(57),m=n(41),_=n(25);var R,g,I,h=Object(f.f)({remove:{id:"lists.account.remove",defaultMessage:"Remove from list"},add:{id:"lists.account.add",defaultMessage:"Add to list"}}),N=Object(v.connect)((function(t,e){var n=e.listId,i=e.added;return{list:t.get("lists").get(n),added:void 0===i?t.getIn(["listAdder","lists","items"]).includes(n):i}}),(function(t,e){var n=e.listId;return{onRemove:function(){return t(Object(j.J)(n))},onAdd:function(){return t(Object(j.A)(n))}}}))(i=Object(f.g)((c=a=function(t){Object(r.a)(n,t);var e;e=n;function n(){return t.apply(this,arguments)||this}return n.prototype.render=function(){var t,e=this.props,n=e.list,i=e.intl,a=e.onRemove,c=e.onAdd;return t=e.added?Object(o.a)(m.a,{icon:"times",title:i.formatMessage(h.remove),onClick:a}):Object(o.a)(m.a,{icon:"plus",title:i.formatMessage(h.add),onClick:c}),Object(o.a)("div",{className:"list"},void 0,Object(o.a)("div",{className:"list__wrapper"},void 0,Object(o.a)("div",{className:"list__display-name"},void 0,Object(o.a)(_.a,{id:"list-ul",className:"column-link__icon",fixedWidth:!0}),n.get("title")),Object(o.a)("div",{className:"account__relationship"},void 0,t)))},n}(b.a),Object(s.a)(a,"propTypes",{list:p.a.map.isRequired,intl:u.a.object.isRequired,onRemove:u.a.func.isRequired,onAdd:u.a.func.isRequired,added:u.a.bool}),Object(s.a)(a,"defaultProps",{added:!1}),i=c))||i)||i,q=n(108),y=n(96),w=n(98);var A,k,M,z=Object(v.connect)((function(){var t=Object(q.d)();return function(e,n){var i=n.accountId;return{account:t(e,i)}}}))(R=Object(f.g)((I=g=function(t){Object(r.a)(n,t);var e;e=n;function n(){return t.apply(this,arguments)||this}return n.prototype.render=function(){var t=this.props.account;return(Object(o.a)("div",{className:"account"},void 0,Object(o.a)("div",{className:"account__wrapper"},void 0,Object(o.a)("div",{className:"account__display-name"},void 0,Object(o.a)("div",{className:"account__avatar-wrapper"},void 0,Object(o.a)(y.a,{account:t,size:36})),Object(o.a)(w.a,{account:t})))))},n}(b.a),Object(s.a)(g,"propTypes",{account:p.a.map.isRequired}),R=I))||R)||R,C=n(1150);var J=Object(O.a)([function(t){return t.get("lists")}],(function(t){return t?t.toList().filter((function(t){return!!t})).sort((function(t,e){return t.get("title").localeCompare(e.get("title"))})):t})),T=Object(v.connect)((function(t){return{listIds:J(t).map((function(t){return t.get("id")}))}}),(function(t){return{onInitialize:function(e){return t(Object(j.N)(e))},onReset:function(){return t(Object(j.L)())}}}))(A=Object(f.g)((M=k=function(t){Object(r.a)(n,t);var e;e=n;function n(){return t.apply(this,arguments)||this}var i=n.prototype;return i.componentDidMount=function(){var t=this.props;(0,t.onInitialize)(t.accountId)},i.componentWillUnmount=function(){(0,this.props.onReset)()},i.render=function(){var t=this.props,e=t.accountId,n=t.listIds;return(Object(o.a)("div",{className:"modal-root__modal list-adder"},void 0,Object(o.a)("div",{className:"list-adder__account"},void 0,Object(o.a)(z,{accountId:e})),Object(o.a)(C.a,{}),Object(o.a)("div",{className:"list-adder__lists"},void 0,n.map((function(t){return Object(o.a)(N,{listId:t},t)})))))},n}(b.a),Object(s.a)(k,"propTypes",{accountId:u.a.string.isRequired,onClose:u.a.func.isRequired,intl:u.a.object.isRequired,onInitialize:u.a.func.isRequired,onReset:u.a.func.isRequired,listIds:p.a.list.isRequired}),A=M))||A)||A}}]);
//# sourceMappingURL=list_adder.js.map

+ 1
- 1
priv/static/packs/features/glitch/async/list_adder.js.map
File diff suppressed because it is too large
View File


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

Loading…
Cancel
Save