Merge branch 'develop' into issue/1383

This commit is contained in:
Maksim Pechnikov 2020-01-22 20:20:39 +03:00
commit cf19bf3c7c
485 changed files with 5044 additions and 1888 deletions

View File

@ -95,6 +95,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Captcha: Enable by default - Captcha: Enable by default
- Mastodon API: Add support for `account_id` param to filter notifications by the account - Mastodon API: Add support for `account_id` param to filter notifications by the account
- Mastodon API: Add `emoji_reactions` property to Statuses - Mastodon API: Add `emoji_reactions` property to Statuses
- Mastodon API: Change emoji reaction reply format
</details> </details>
### Fixed ### Fixed

View File

@ -98,7 +98,6 @@ config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"], shortcode_globs: ["/emoji/custom/**/*.png"],
pack_extensions: [".png", ".gif"], pack_extensions: [".png", ".gif"],
groups: [ groups: [
# Put groups that have higher priority than defaults here. Example in `docs/config/custom_emoji.md`
Custom: ["/emoji/*.png", "/emoji/**/*.png"] Custom: ["/emoji/*.png", "/emoji/**/*.png"]
], ],
default_manifest: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json", default_manifest: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json",
@ -251,7 +250,6 @@ config :pleroma, :instance,
remote_post_retention_days: 90, remote_post_retention_days: 90,
skip_thread_containment: true, skip_thread_containment: true,
limit_to_local_content: :unauthenticated, limit_to_local_content: :unauthenticated,
dynamic_configuration: false,
user_bio_length: 5000, user_bio_length: 5000,
user_name_length: 100, user_name_length: 100,
max_account_fields: 10, max_account_fields: 10,
@ -610,6 +608,8 @@ config :pleroma, :web_cache_ttl,
config :pleroma, :modules, runtime_dir: "instance/modules" config :pleroma, :modules, runtime_dir: "instance/modules"
config :pleroma, configurable_from_database: false
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,8 @@ config :pleroma, :modules, runtime_dir: "/var/lib/pleroma/modules"
config_path = System.get_env("PLEROMA_CONFIG_PATH") || "/etc/pleroma/config.exs" config_path = System.get_env("PLEROMA_CONFIG_PATH") || "/etc/pleroma/config.exs"
config :pleroma, release: true, config_path: config_path
if File.exists?(config_path) do if File.exists?(config_path) do
import_config config_path import_config config_path
else else
@ -18,3 +20,12 @@ else
IO.puts(warning) IO.puts(warning)
end end
exported_config =
config_path
|> Path.dirname()
|> Path.join("prod.exported_from_db.secret.exs")
if File.exists?(exported_config) do
import_config exported_config
end

View File

@ -665,27 +665,16 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- 404 Not Found `"Not found"` - 404 Not Found `"Not found"`
- On success: 200 OK `{}` - On success: 200 OK `{}`
## `GET /api/pleroma/admin/config/migrate_to_db`
### Run mix task pleroma.config migrate_to_db
Copy settings on key `:pleroma` to DB.
- Params: none
- Response:
```json
{}
```
## `GET /api/pleroma/admin/config/migrate_from_db` ## `GET /api/pleroma/admin/config/migrate_from_db`
### Run mix task pleroma.config migrate_from_db ### Run mix task pleroma.config migrate_from_db
Copy all settings from DB to `config/prod.exported_from_db.secret.exs` with deletion from DB. Copies all settings from database to `config/{env}.exported_from_db.secret.exs` with deletion from the table. Where `{env}` is the environment in which `pleroma` is running.
- Params: none - Params: none
- Response: - Response:
- On failure:
- 400 Bad Request `"To use this endpoint you need to enable configuration from database."`
```json ```json
{} {}
@ -693,20 +682,24 @@ Copy all settings from DB to `config/prod.exported_from_db.secret.exs` with dele
## `GET /api/pleroma/admin/config` ## `GET /api/pleroma/admin/config`
### List config settings ### Get list of merged default settings with saved in database.
List config settings only works with `:pleroma => :instance => :dynamic_configuration` setting to `true`. **Only works when configuration from database is enabled.**
- Params: none - Params:
- `only_db`: true (*optional*, get only saved in database settings)
- Response: - Response:
- On failure:
- 400 Bad Request `"To use this endpoint you need to enable configuration from database."`
- 400 Bad Request `"To use configuration from database migrate your settings to database."`
```json ```json
{ {
configs: [ configs: [
{ {
"group": string, "group": ":pleroma",
"key": string or string with leading `:` for atoms, "key": "Pleroma.Upload",
"value": string or {} or [] or {"tuple": []} "value": []
} }
] ]
} }
@ -716,44 +709,107 @@ List config settings only works with `:pleroma => :instance => :dynamic_configur
### Update config settings ### Update config settings
Updating config settings only works with `:pleroma => :instance => :dynamic_configuration` setting to `true`. **Only works when configuration from database is enabled.**
Module name can be passed as string, which starts with `Pleroma`, e.g. `"Pleroma.Upload"`.
Atom keys and values can be passed with `:` in the beginning, e.g. `":upload"`.
Tuples can be passed as `{"tuple": ["first_val", Pleroma.Module, []]}`.
`{"tuple": ["some_string", "Pleroma.Some.Module", []]}` will be converted to `{"some_string", Pleroma.Some.Module, []}`.
Keywords can be passed as lists with 2 child tuples, e.g.
`[{"tuple": ["first_val", Pleroma.Module]}, {"tuple": ["second_val", true]}]`.
If value contains list of settings `[subkey: val1, subkey2: val2, subkey3: val3]`, it's possible to remove only subkeys instead of all settings passing `subkeys` parameter. E.g.: Some modifications are necessary to save the config settings correctly:
{"group": "pleroma", "key": "some_key", "delete": "true", "subkeys": [":subkey", ":subkey3"]}.
Compile time settings (need instance reboot): - strings which start with `Pleroma.`, `Phoenix.`, `Tesla.` or strings like `Oban`, `Ueberauth` will be converted to modules;
- all settings by this keys: ```
"Pleroma.Upload" -> Pleroma.Upload
"Oban" -> Oban
```
- strings starting with `:` will be converted to atoms;
```
":pleroma" -> :pleroma
```
- objects with `tuple` key and array value will be converted to tuples;
```
{"tuple": ["string", "Pleroma.Upload", []]} -> {"string", Pleroma.Upload, []}
```
- arrays with *tuple objects* will be converted to keywords;
```
[{"tuple": [":key1", "value"]}, {"tuple": [":key2", "value"]}] -> [key1: "value", key2: "value"]
```
Most of the settings will be applied in `runtime`, this means that you don't need to restart the instance. But some settings are applied in `compile time` and require a reboot of the instance, such as:
- all settings inside these keys:
- `:hackney_pools` - `:hackney_pools`
- `:chat` - `:chat`
- `Pleroma.Web.Endpoint` - partially settings inside these keys:
- `Pleroma.Repo` - `:seconds_valid` in `Pleroma.Captcha`
- part settings: - `:proxy_remote` in `Pleroma.Upload`
- `Pleroma.Captcha` -> `:seconds_valid` - `:upload_limit` in `:instance`
- `Pleroma.Upload` -> `:proxy_remote`
- `:instance` -> `:upload_limit`
- Params: - Params:
- `configs` => [ - `configs` - array of config objects
- `group` (string) - config object params:
- `key` (string or string with leading `:` for atoms) - `group` - string (**required**)
- `value` (string, [], {} or {"tuple": []}) - `key` - string (**required**)
- `delete` = true (optional, if parameter must be deleted) - `value` - string, [], {} or {"tuple": []} (**required**)
- `subkeys` [(string with leading `:` for atoms)] (optional, works only if `delete=true` parameter is passed, otherwise will be ignored) - `delete` - true (*optional*, if setting must be deleted)
] - `subkeys` - array of strings (*optional*, only works when `delete=true` parameter is passed, otherwise will be ignored)
- Request (example): *When a value have several nested settings, you can delete only some nested settings by passing a parameter `subkeys`, without deleting all settings by key.*
```
[subkey: val1, subkey2: val2, subkey3: val3] \\ initial value
{"group": ":pleroma", "key": "some_key", "delete": true, "subkeys": [":subkey", ":subkey3"]} \\ passing json for deletion
[subkey2: val2] \\ value after deletion
```
*Most of the settings can be partially updated through merge old values with new values, except settings value of which is list or is not keyword.*
Example of setting without keyword in value:
```elixir
config :tesla, :adapter, Tesla.Adapter.Hackney
```
List of settings which support only full update by key:
```elixir
@full_key_update [
{:pleroma, :ecto_repos},
{:quack, :meta},
{:mime, :types},
{:cors_plug, [:max_age, :methods, :expose, :headers]},
{:auto_linker, :opts},
{:swarm, :node_blacklist},
{:logger, :backends}
]
```
List of settings which support only full update by subkey:
```elixir
@full_subkey_update [
{:pleroma, :assets, :mascots},
{:pleroma, :emoji, :groups},
{:pleroma, :workers, :retries},
{:pleroma, :mrf_subchain, :match_actor},
{:pleroma, :mrf_keyword, :replace}
]
```
*Settings without explicit key must be sended in separate config object params.*
```elixir
config :quack,
level: :debug,
meta: [:all],
...
```
```json
{
configs: [
{"group": ":quack", "key": ":level", "value": ":debug"},
{"group": ":quack", "key": ":meta", "value": [":all"]},
...
]
}
```
- Request:
```json ```json
{ {
configs: [ configs: [
{ {
"group": "pleroma", "group": ":pleroma",
"key": "Pleroma.Upload", "key": "Pleroma.Upload",
"value": [ "value": [
{"tuple": [":uploader", "Pleroma.Uploaders.Local"]}, {"tuple": [":uploader", "Pleroma.Uploaders.Local"]},
@ -763,7 +819,7 @@ Compile time settings (need instance reboot):
{"tuple": [":proxy_opts", [ {"tuple": [":proxy_opts", [
{"tuple": [":redirect_on_failure", false]}, {"tuple": [":redirect_on_failure", false]},
{"tuple": [":max_body_length", 1048576]}, {"tuple": [":max_body_length", 1048576]},
{"tuple": [":http": [ {"tuple": [":http", [
{"tuple": [":follow_redirect", true]}, {"tuple": [":follow_redirect", true]},
{"tuple": [":pool", ":upload"]}, {"tuple": [":pool", ":upload"]},
]]} ]]}
@ -779,19 +835,53 @@ Compile time settings (need instance reboot):
``` ```
- Response: - Response:
- On failure:
- 400 Bad Request `"To use this endpoint you need to enable configuration from database."`
```json ```json
{ {
configs: [ configs: [
{ {
"group": string, "group": ":pleroma",
"key": string or string with leading `:` for atoms, "key": "Pleroma.Upload",
"value": string or {} or [] or {"tuple": []} "value": [...]
} }
] ]
} }
``` ```
## ` GET /api/pleroma/admin/config/descriptions`
### Get JSON with config descriptions.
Loads json generated from `config/descriptions.exs`.
- Params: none
- Response:
```json
[{
"group": ":pleroma", // string
"key": "ModuleName", // string
"type": "group", // string or list with possible values,
"description": "Upload general settings", // string
"children": [
{
"key": ":uploader", // string or module name `Pleroma.Upload`
"type": "module",
"description": "Module which will be used for uploads",
"suggestions": ["module1", "module2"]
},
{
"key": ":filters",
"type": ["list", "module"],
"description": "List of filter modules for uploads",
"suggestions": [
"module1", "module2", "module3"
]
}
]
}]
```
## `GET /api/pleroma/admin/moderation_log` ## `GET /api/pleroma/admin/moderation_log`
### Get moderation log ### Get moderation log

View File

@ -29,7 +29,7 @@ Has these additional fields under the `pleroma` object:
- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain` - `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
- `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire - `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
- `thread_muted`: true if the thread the post belongs to is muted - `thread_muted`: true if the thread the post belongs to is muted
- `emoji_reactions`: An object with all the emoji reactions with count. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint. - `emoji_reactions`: A list with emoji / reaction count tuples. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint.
## Attachments ## Attachments

View File

@ -451,11 +451,11 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
* Method: `GET` * Method: `GET`
* Authentication: optional * Authentication: optional
* Params: None * Params: None
* Response: JSON, a map of emoji to account list mappings. * Response: JSON, a list of emoji/account list tuples, sorted by emoji insertion date, in ascending order, e.g, the first emoji in the list is the oldest.
* Example Response: * Example Response:
```json ```json
{ [
"😀" => [{"id" => "xyz.."...}, {"id" => "zyx..."}], ["😀", [{"id" => "xyz.."...}, {"id" => "zyx..."}]],
"🗡" => [{"id" => "abc..."}] ["☕", [{"id" => "abc..."}]]
} ]
``` ```

79
docs/admin/config.md Normal file
View File

@ -0,0 +1,79 @@
# Configuring instance
You can configure your instance from admin interface. You need account with admin rights and little change in config file, which will allow settings configuration from database.
```elixir
config :pleroma, configurable_from_database: true
```
## How it works
Settings are stored in database and are applied in `runtime` after each change. Most of the settings take effect immediately, except some, which need instance reboot. These settings are needed in `compile time`, that's why settings are duplicated to the file.
File with duplicated settings is located in `config/{env}.exported_from_db.exs` if pleroma is runned from source. For prod env it will be `config/prod.exported_from_db.exs`.
For releases: `/etc/pleroma/prod.exported_from_db.secret.exs` or `PLEROMA_CONFIG_PATH/prod.exported_from_db.exs`.
## How to set it up
You need to migrate your existing settings to the database. This task will migrate only added by user settings.
For example you add settings to `prod.secret.exs` file, only these settings will be migrated to database. For release it will be `/etc/pleroma/config.exs` or `PLEROMA_CONFIG_PATH`.
You can do this with mix task (all config files will remain untouched):
```sh tab="OTP"
./bin/pleroma_ctl config migrate_to_db
```
```sh tab="From Source"
mix pleroma.config migrate_to_db
```
Now you can change settings in admin interface. After each save, settings from database are duplicated to the `config/{env}.exported_from_db.exs` file.
<span style="color:red">**ATTENTION**</span>
**<span style="color:red">Be careful while changing the settings. Every inaccurate configuration change can break the federation or the instance load.</span>**
*Compile time settings, which require instance reboot and can break instance loading:*
- all settings inside these keys:
- `:hackney_pools`
- `:chat`
- partially settings inside these keys:
- `:seconds_valid` in `Pleroma.Captcha`
- `:proxy_remote` in `Pleroma.Upload`
- `:upload_limit` in `:instance`
## How to dump settings from database to file
*Adding `-d` flag will delete migrated settings from database table.*
```sh tab="OTP"
./bin/pleroma_ctl config migrate_from_db [-d]
```
```sh tab="From Source"
mix pleroma.config migrate_from_db [-d]
```
## How to completely remove it
1. Truncate or delete all values from `config` table
```sql
TRUNCATE TABLE config;
```
2. Delete `config/{env}.exported_from_db.exs`.
For `prod` env:
```bash
cd /opt/pleroma
cp config/prod.exported_from_db.exs config/exported_from_db.back
rm -rf config/prod.exported_from_db.exs
```
*If you don't want to backup settings, you can skip step with `cp` command.*
3. Set configurable_from_database to `false`.
```elixir
config :pleroma, configurable_from_database: false
```
4. Restart pleroma instance
```bash
sudo service pleroma restart
```

View File

@ -18,11 +18,11 @@ mix pleroma.config migrate_to_db
## Transfer config from DB to `config/env.exported_from_db.secret.exs` ## Transfer config from DB to `config/env.exported_from_db.secret.exs`
To delete transfered settings from database optional flag `-d` can be used. <env> is `prod` by default.
```sh tab="OTP" ```sh tab="OTP"
./bin/pleroma_ctl config migrate_from_db <env> ./bin/pleroma_ctl config migrate_from_db [--env=<env>] [-d]
``` ```
```sh tab="From Source" ```sh tab="From Source"
mix pleroma.config migrate_from_db <env> mix pleroma.config migrate_from_db [--env=<env>] [-d]
``` ```

View File

@ -70,11 +70,6 @@ You shouldn't edit the base config directly to avoid breakages and merge conflic
* `account_field_value_length`: An account field value maximum length (default: `2048`). * `account_field_value_length`: An account field value maximum length (default: `2048`).
* `external_user_synchronization`: Enabling following/followers counters synchronization for external users. * `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
!!! danger
This is a Work In Progress, not usable just yet
* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api.
## Federation ## Federation
### MRF policies ### MRF policies
@ -355,7 +350,7 @@ Available caches:
* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`) * `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`)
* `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`) * `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`)
* `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default` * `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default`
* `adapter`: array of hackney options * `adapter`: array of hackney options
@ -850,3 +845,7 @@ config :auto_linker,
## Custom Runtime Modules (`:modules`) ## Custom Runtime Modules (`:modules`)
* `runtime_dir`: A path to custom Elixir modules (such as MRF policies). * `runtime_dir`: A path to custom Elixir modules (such as MRF policies).
## :configurable_from_database
Enable/disable configuration from database.

View File

@ -4,71 +4,144 @@
defmodule Mix.Tasks.Pleroma.Config do defmodule Mix.Tasks.Pleroma.Config do
use Mix.Task use Mix.Task
import Mix.Pleroma import Mix.Pleroma
alias Pleroma.ConfigDB
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Web.AdminAPI.Config
@shortdoc "Manages the location of the config" @shortdoc "Manages the location of the config"
@moduledoc File.read!("docs/administration/CLI_tasks/config.md") @moduledoc File.read!("docs/administration/CLI_tasks/config.md")
def run(["migrate_to_db"]) do def run(["migrate_to_db"]) do
start_pleroma() start_pleroma()
migrate_to_db()
if Pleroma.Config.get([:instance, :dynamic_configuration]) do
Application.get_all_env(:pleroma)
|> Enum.reject(fn {k, _v} -> k in [Pleroma.Repo, :env] end)
|> Enum.each(fn {k, v} ->
key = to_string(k) |> String.replace("Elixir.", "")
key =
if String.starts_with?(key, "Pleroma.") do
key
else
":" <> key
end
{:ok, _} = Config.update_or_create(%{group: "pleroma", key: key, value: v})
Mix.shell().info("#{key} is migrated.")
end)
Mix.shell().info("Settings migrated.")
else
Mix.shell().info(
"Migration is not allowed by config. You can change this behavior in instance settings."
)
end
end end
def run(["migrate_from_db", env, delete?]) do def run(["migrate_from_db" | options]) do
start_pleroma() start_pleroma()
delete? = if delete? == "true", do: true, else: false {opts, _} =
OptionParser.parse!(options,
if Pleroma.Config.get([:instance, :dynamic_configuration]) do strict: [env: :string, delete: :boolean],
config_path = "config/#{env}.exported_from_db.secret.exs" aliases: [d: :delete]
{:ok, file} = File.open(config_path, [:write, :utf8])
IO.write(file, "use Mix.Config\r\n")
Repo.all(Config)
|> Enum.each(fn config ->
IO.write(
file,
"config :#{config.group}, #{config.key}, #{
inspect(Config.from_binary(config.value), limit: :infinity)
}\r\n\r\n"
)
if delete? do
{:ok, _} = Repo.delete(config)
Mix.shell().info("#{config.key} deleted from DB.")
end
end)
File.close(file)
System.cmd("mix", ["format", config_path])
else
Mix.shell().info(
"Migration is not allowed by config. You can change this behavior in instance settings."
) )
migrate_from_db(opts)
end
@spec migrate_to_db(Path.t() | nil) :: any()
def migrate_to_db(file_path \\ nil) do
if Pleroma.Config.get([:configurable_from_database]) do
config_file =
if file_path do
file_path
else
if Pleroma.Config.get(:release) do
Pleroma.Config.get(:config_path)
else
"config/#{Pleroma.Config.get(:env)}.secret.exs"
end
end
do_migrate_to_db(config_file)
else
migration_error()
end end
end end
defp do_migrate_to_db(config_file) do
if File.exists?(config_file) do
custom_config =
config_file
|> read_file()
|> elem(0)
custom_config
|> Keyword.keys()
|> Enum.each(&create(&1, custom_config))
else
shell_info("To migrate settings, you must define custom settings in #{config_file}.")
end
end
defp create(group, settings) do
group
|> Pleroma.Config.Loader.filter_group(settings)
|> Enum.each(fn {key, value} ->
key = inspect(key)
{:ok, _} = ConfigDB.update_or_create(%{group: inspect(group), key: key, value: value})
shell_info("Settings for key #{key} migrated.")
end)
shell_info("Settings for group :#{group} migrated.")
end
defp migrate_from_db(opts) do
if Pleroma.Config.get([:configurable_from_database]) do
env = opts[:env] || "prod"
config_path =
if Pleroma.Config.get(:release) do
:config_path
|> Pleroma.Config.get()
|> Path.dirname()
else
"config"
end
|> Path.join("#{env}.exported_from_db.secret.exs")
file = File.open!(config_path, [:write, :utf8])
IO.write(file, config_header())
ConfigDB
|> Repo.all()
|> Enum.each(&write_and_delete(&1, file, opts[:delete]))
:ok = File.close(file)
System.cmd("mix", ["format", config_path])
else
migration_error()
end
end
defp migration_error do
shell_error(
"Migration is not allowed in config. You can change this behavior by setting `configurable_from_database` to true."
)
end
if Code.ensure_loaded?(Config.Reader) do
defp config_header, do: "import Config\r\n\r\n"
defp read_file(config_file), do: Config.Reader.read_imports!(config_file)
else
defp config_header, do: "use Mix.Config\r\n\r\n"
defp read_file(config_file), do: Mix.Config.eval!(config_file)
end
defp write_and_delete(config, file, delete?) do
config
|> write(file)
|> delete(delete?)
end
defp write(config, file) do
value =
config.value
|> ConfigDB.from_binary()
|> inspect(limit: :infinity)
IO.write(file, "config #{config.group}, #{config.key}, #{value}\r\n\r\n")
config
end
defp delete(config, true) do
{:ok, _} = Repo.delete(config)
shell_info("#{config.key} deleted from DB.")
end
defp delete(_config, _), do: :ok
end end

View File

@ -28,7 +28,7 @@ defmodule Mix.Tasks.Pleroma.Docs do
defp do_run(implementation) do defp do_run(implementation) do
start_pleroma() start_pleroma()
with {descriptions, _paths} <- Mix.Config.eval!("config/description.exs"), with descriptions <- Pleroma.Config.Loader.load("config/description.exs"),
{:ok, file_path} <- {:ok, file_path} <-
Pleroma.Docs.Generator.process( Pleroma.Docs.Generator.process(
implementation, implementation,

View File

@ -0,0 +1,422 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ConfigDB do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
import Pleroma.Web.Gettext
alias __MODULE__
alias Pleroma.Repo
@type t :: %__MODULE__{}
@full_key_update [
{:pleroma, :ecto_repos},
{:quack, :meta},
{:mime, :types},
{:cors_plug, [:max_age, :methods, :expose, :headers]},
{:auto_linker, :opts},
{:swarm, :node_blacklist},
{:logger, :backends}
]
@full_subkey_update [
{:pleroma, :assets, :mascots},
{:pleroma, :emoji, :groups},
{:pleroma, :workers, :retries},
{:pleroma, :mrf_subchain, :match_actor},
{:pleroma, :mrf_keyword, :replace}
]
@regex ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u
@delimiters ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}]
schema "config" do
field(:key, :string)
field(:group, :string)
field(:value, :binary)
field(:db, {:array, :string}, virtual: true, default: [])
timestamps()
end
@spec get_all_as_keyword() :: keyword()
def get_all_as_keyword do
ConfigDB
|> select([c], {c.group, c.key, c.value})
|> Repo.all()
|> Enum.reduce([], fn {group, key, value}, acc ->
group = ConfigDB.from_string(group)
key = ConfigDB.from_string(key)
value = from_binary(value)
Keyword.update(acc, group, [{key, value}], &Keyword.merge(&1, [{key, value}]))
end)
end
@spec get_by_params(map()) :: ConfigDB.t() | nil
def get_by_params(params), do: Repo.get_by(ConfigDB, params)
@spec changeset(ConfigDB.t(), map()) :: Changeset.t()
def changeset(config, params \\ %{}) do
params = Map.put(params, :value, transform(params[:value]))
config
|> cast(params, [:key, :group, :value])
|> validate_required([:key, :group, :value])
|> unique_constraint(:key, name: :config_group_key_index)
end
@spec create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
def create(params) do
%ConfigDB{}
|> changeset(params)
|> Repo.insert()
end
@spec update(ConfigDB.t(), map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
def update(%ConfigDB{} = config, %{value: value}) do
config
|> changeset(%{value: value})
|> Repo.update()
end
@spec get_db_keys(ConfigDB.t()) :: [String.t()]
def get_db_keys(%ConfigDB{} = config) do
config.value
|> ConfigDB.from_binary()
|> get_db_keys(config.key)
end
@spec get_db_keys(keyword(), any()) :: [String.t()]
def get_db_keys(value, key) do
if Keyword.keyword?(value) do
value |> Keyword.keys() |> Enum.map(&convert(&1))
else
[convert(key)]
end
end
@spec merge_group(atom(), atom(), keyword(), keyword()) :: keyword()
def merge_group(group, key, old_value, new_value) do
new_keys = to_map_set(new_value)
intersect_keys =
old_value |> to_map_set() |> MapSet.intersection(new_keys) |> MapSet.to_list()
merged_value = ConfigDB.merge(old_value, new_value)
@full_subkey_update
|> Enum.map(fn
{g, k, subkey} when g == group and k == key ->
if subkey in intersect_keys, do: subkey, else: []
_ ->
[]
end)
|> List.flatten()
|> Enum.reduce(merged_value, fn subkey, acc ->
Keyword.put(acc, subkey, new_value[subkey])
end)
end
defp to_map_set(keyword) do
keyword
|> Keyword.keys()
|> MapSet.new()
end
@spec sub_key_full_update?(atom(), atom(), [Keyword.key()]) :: boolean()
def sub_key_full_update?(group, key, subkeys) do
Enum.any?(@full_subkey_update, fn {g, k, subkey} ->
g == group and k == key and subkey in subkeys
end)
end
@spec merge(keyword(), keyword()) :: keyword()
def merge(config1, config2) when is_list(config1) and is_list(config2) do
Keyword.merge(config1, config2, fn _, app1, app2 ->
if Keyword.keyword?(app1) and Keyword.keyword?(app2) do
Keyword.merge(app1, app2, &deep_merge/3)
else
app2
end
end)
end
defp deep_merge(_key, value1, value2) do
if Keyword.keyword?(value1) and Keyword.keyword?(value2) do
Keyword.merge(value1, value2, &deep_merge/3)
else
value2
end
end
@spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
def update_or_create(params) do
search_opts = Map.take(params, [:group, :key])
with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts),
{:partial_update, true, config} <-
{:partial_update, can_be_partially_updated?(config), config},
old_value <- from_binary(config.value),
transformed_value <- do_transform(params[:value]),
{:can_be_merged, true, config} <- {:can_be_merged, is_list(transformed_value), config},
new_value <-
merge_group(
ConfigDB.from_string(config.group),
ConfigDB.from_string(config.key),
old_value,
transformed_value
) do
ConfigDB.update(config, %{value: new_value})
else
{reason, false, config} when reason in [:partial_update, :can_be_merged] ->
ConfigDB.update(config, params)
nil ->
ConfigDB.create(params)
end
end
defp can_be_partially_updated?(%ConfigDB{} = config), do: not only_full_update?(config)
defp only_full_update?(%ConfigDB{} = config) do
config_group = ConfigDB.from_string(config.group)
config_key = ConfigDB.from_string(config.key)
Enum.any?(@full_key_update, fn
{group, key} when is_list(key) ->
config_group == group and config_key in key
{group, key} ->
config_group == group and config_key == key
end)
end
@spec delete(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
def delete(params) do
search_opts = Map.delete(params, :subkeys)
with %ConfigDB{} = config <- ConfigDB.get_by_params(search_opts),
{config, sub_keys} when is_list(sub_keys) <- {config, params[:subkeys]},
old_value <- from_binary(config.value),
keys <- Enum.map(sub_keys, &do_transform_string(&1)),
{:partial_remove, config, new_value} when new_value != [] <-
{:partial_remove, config, Keyword.drop(old_value, keys)} do
ConfigDB.update(config, %{value: new_value})
else
{:partial_remove, config, []} ->
Repo.delete(config)
{config, nil} ->
Repo.delete(config)
nil ->
err =
dgettext("errors", "Config with params %{params} not found", params: inspect(params))
{:error, err}
end
end
@spec from_binary(binary()) :: term()
def from_binary(binary), do: :erlang.binary_to_term(binary)
@spec from_binary_with_convert(binary()) :: any()
def from_binary_with_convert(binary) do
binary
|> from_binary()
|> do_convert()
end
@spec from_string(String.t()) :: atom() | no_return()
def from_string(":" <> entity), do: String.to_existing_atom(entity)
def from_string(entity) when is_binary(entity) do
if is_module_name?(entity) do
String.to_existing_atom("Elixir.#{entity}")
else
entity
end
end
@spec convert(any()) :: any()
def convert(entity), do: do_convert(entity)
defp do_convert(entity) when is_list(entity) do
for v <- entity, into: [], do: do_convert(v)
end
defp do_convert(%Regex{} = entity), do: inspect(entity)
defp do_convert(entity) when is_map(entity) do
for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)}
end
defp do_convert({:proxy_url, {type, :localhost, port}}) do
%{"tuple" => [":proxy_url", %{"tuple" => [do_convert(type), "localhost", port]}]}
end
defp do_convert({:proxy_url, {type, host, port}}) when is_tuple(host) do
ip =
host
|> :inet_parse.ntoa()
|> to_string()
%{
"tuple" => [
":proxy_url",
%{"tuple" => [do_convert(type), ip, port]}
]
}
end
defp do_convert({:proxy_url, {type, host, port}}) do
%{
"tuple" => [
":proxy_url",
%{"tuple" => [do_convert(type), to_string(host), port]}
]
}
end
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
defp do_convert(entity) when is_tuple(entity) do
value =
entity
|> Tuple.to_list()
|> do_convert()
%{"tuple" => value}
end
defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity) do
entity
end
defp do_convert(entity)
when is_atom(entity) and entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do
":#{entity}"
end
defp do_convert(entity) when is_atom(entity), do: inspect(entity)
defp do_convert(entity) when is_binary(entity), do: entity
@spec transform(any()) :: binary() | no_return()
def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do
entity
|> do_transform()
|> to_binary()
end
def transform(entity), do: to_binary(entity)
@spec transform_with_out_binary(any()) :: any()
def transform_with_out_binary(entity), do: do_transform(entity)
@spec to_binary(any()) :: binary()
def to_binary(entity), do: :erlang.term_to_binary(entity)
defp do_transform(%Regex{} = entity), do: entity
defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do
{:proxy_url, {do_transform_string(type), parse_host(host), port}}
end
defp do_transform(%{"tuple" => [":partial_chain", entity]}) do
{partial_chain, []} =
entity
|> String.replace(~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
|> Code.eval_string()
{:partial_chain, partial_chain}
end
defp do_transform(%{"tuple" => entity}) do
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
end
defp do_transform(entity) when is_map(entity) do
for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)}
end
defp do_transform(entity) when is_list(entity) do
for v <- entity, into: [], do: do_transform(v)
end
defp do_transform(entity) when is_binary(entity) do
entity
|> String.trim()
|> do_transform_string()
end
defp do_transform(entity), do: entity
defp parse_host("localhost"), do: :localhost
defp parse_host(host) do
charlist = to_charlist(host)
case :inet.parse_address(charlist) do
{:error, :einval} ->
charlist
{:ok, ip} ->
ip
end
end
defp find_valid_delimiter([], _string, _) do
raise(ArgumentError, message: "valid delimiter for Regex expression not found")
end
defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter)
when is_tuple(delimiter) do
if String.contains?(pattern, closing) do
find_valid_delimiter(others, pattern, regex_delimiter)
else
{:ok, {leading, closing}}
end
end
defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do
if String.contains?(pattern, delimiter) do
find_valid_delimiter(others, pattern, regex_delimiter)
else
{:ok, {delimiter, delimiter}}
end
end
defp do_transform_string("~r" <> _pattern = regex) do
with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <-
Regex.named_captures(@regex, regex),
{:ok, {leading, closing}} <- find_valid_delimiter(@delimiters, pattern, regex_delimiter),
{result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do
result
end
end
defp do_transform_string(":" <> atom), do: String.to_atom(atom)
defp do_transform_string(value) do
if is_module_name?(value) do
String.to_existing_atom("Elixir." <> value)
else
value
end
end
@spec is_module_name?(String.t()) :: boolean()
def is_module_name?(string) do
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth)\./, string) or
string in ["Oban", "Ueberauth", "ExSyslogger"]
end
end

View File

@ -0,0 +1,16 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.Holder do
@config Pleroma.Config.Loader.load_and_merge()
@spec config() :: keyword()
def config, do: @config
@spec config(atom()) :: any()
def config(group), do: @config[group]
@spec config(atom(), atom()) :: any()
def config(group, key), do: @config[group][key]
end

View File

@ -0,0 +1,59 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.Loader do
@paths ["config/config.exs", "config/#{Mix.env()}.exs"]
@reject_keys [
Pleroma.Repo,
Pleroma.Web.Endpoint,
:env,
:configurable_from_database,
:database,
:swarm
]
if Code.ensure_loaded?(Config.Reader) do
@spec load(Path.t()) :: keyword()
def load(path), do: Config.Reader.read!(path)
defp do_merge(conf1, conf2), do: Config.Reader.merge(conf1, conf2)
else
# support for Elixir less than 1.9
@spec load(Path.t()) :: keyword()
def load(path) do
path
|> Mix.Config.eval!()
|> elem(0)
end
defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2)
end
@spec load_and_merge() :: keyword()
def load_and_merge do
all_paths =
if Pleroma.Config.get(:release),
do: @paths ++ ["config/releases.exs"],
else: @paths
all_paths
|> Enum.map(&load(&1))
|> Enum.reduce([], &do_merge(&2, &1))
|> filter()
end
defp filter(configs) do
configs
|> Keyword.keys()
|> Enum.reduce([], &Keyword.put(&2, &1, filter_group(&1, configs)))
end
@spec filter_group(atom(), keyword()) :: keyword()
def filter_group(group, configs) do
Enum.reject(configs[group], fn {key, _v} ->
key in @reject_keys or (group == :phoenix and key == :serve_endpoints)
end)
end
end

View File

@ -4,56 +4,111 @@
defmodule Pleroma.Config.TransferTask do defmodule Pleroma.Config.TransferTask do
use Task use Task
alias Pleroma.Web.AdminAPI.Config
alias Pleroma.ConfigDB
alias Pleroma.Repo
require Logger
def start_link(_) do def start_link(_) do
load_and_update_env() load_and_update_env()
if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Pleroma.Repo) if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
:ignore :ignore
end end
def load_and_update_env do @spec load_and_update_env([ConfigDB.t()]) :: :ok | false
if Pleroma.Config.get([:instance, :dynamic_configuration]) and def load_and_update_env(deleted \\ []) do
Ecto.Adapters.SQL.table_exists?(Pleroma.Repo, "config") do with true <- Pleroma.Config.get(:configurable_from_database),
for_restart = true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"),
Pleroma.Repo.all(Config) started_applications <- Application.started_applications() do
|> Enum.map(&update_env(&1))
# We need to restart applications for loaded settings take effect # We need to restart applications for loaded settings take effect
for_restart in_db = Repo.all(ConfigDB)
|> Enum.reject(&(&1 in [:pleroma, :ok]))
|> Enum.each(fn app -> with_deleted = in_db ++ deleted
Application.stop(app)
:ok = Application.start(app) with_deleted
end) |> Enum.map(&merge_and_update(&1))
|> Enum.uniq()
# TODO: some problem with prometheus after restart!
|> Enum.reject(&(&1 in [:pleroma, nil, :prometheus]))
|> Enum.each(&restart(started_applications, &1))
:ok
end end
end end
defp update_env(setting) do defp merge_and_update(setting) do
try do try do
key = key = ConfigDB.from_string(setting.key)
if String.starts_with?(setting.key, "Pleroma.") do group = ConfigDB.from_string(setting.group)
"Elixir." <> setting.key
default = Pleroma.Config.Holder.config(group, key)
merged_value = merge_value(setting, default, group, key)
:ok = update_env(group, key, merged_value)
if group != :logger do
group
else
# change logger configuration in runtime, without restart
if Keyword.keyword?(merged_value) and
key not in [:compile_time_application, :backends, :compile_time_purge_matching] do
Logger.configure_backend(key, merged_value)
else else
String.trim_leading(setting.key, ":") Logger.configure([{key, merged_value}])
end end
group = String.to_existing_atom(setting.group) nil
end
Application.put_env(
group,
String.to_existing_atom(key),
Config.from_binary(setting.value)
)
group
rescue rescue
e -> error ->
require Logger error_msg =
"updating env causes error, group: " <>
inspect(setting.group) <>
" key: " <>
inspect(setting.key) <>
" value: " <>
inspect(ConfigDB.from_binary(setting.value)) <> " error: " <> inspect(error)
Logger.warn( Logger.warn(error_msg)
"updating env causes error, key: #{inspect(setting.key)}, error: #{inspect(e)}"
) nil
end end
end end
defp merge_value(%{__meta__: %{state: :deleted}}, default, _group, _key), do: default
defp merge_value(setting, default, group, key) do
value = ConfigDB.from_binary(setting.value)
if can_be_merged?(default, value) do
ConfigDB.merge_group(group, key, default, value)
else
value
end
end
defp update_env(group, key, nil), do: Application.delete_env(group, key)
defp update_env(group, key, value), do: Application.put_env(group, key, value)
defp restart(started_applications, app) do
with {^app, _, _} <- List.keyfind(started_applications, app, 0),
:ok <- Application.stop(app) do
:ok = Application.start(app)
else
nil ->
Logger.warn("#{app} is not started.")
error ->
error
|> inspect()
|> Logger.warn()
end
end
defp can_be_merged?(val1, val2) when is_list(val1) and is_list(val2) do
Keyword.keyword?(val1) and Keyword.keyword?(val2)
end
defp can_be_merged?(_val1, _val2), do: false
end end

View File

@ -6,68 +6,116 @@ defmodule Pleroma.Docs.Generator do
implementation.process(descriptions) implementation.process(descriptions)
end end
@spec uploaders_list() :: [module()] @spec list_modules_in_dir(String.t(), String.t()) :: [module()]
def uploaders_list do def list_modules_in_dir(dir, start) do
{:ok, modules} = :application.get_key(:pleroma, :modules) with {:ok, files} <- File.ls(dir) do
files
Enum.filter(modules, fn module -> |> Enum.filter(&String.ends_with?(&1, ".ex"))
name_as_list = Module.split(module) |> Enum.map(fn filename ->
module = filename |> String.trim_trailing(".ex") |> Macro.camelize()
List.starts_with?(name_as_list, ["Pleroma", "Uploaders"]) and String.to_existing_atom(start <> module)
List.last(name_as_list) != "Uploader" end)
end) end
end end
@spec filters_list() :: [module()] @doc """
def filters_list do Converts:
{:ok, modules} = :application.get_key(:pleroma, :modules) - atoms to strings with leading `:`
- module names to strings, without leading `Elixir.`
Enum.filter(modules, fn module -> - add humanized labels to `keys` if label is not defined, e.g. `:instance` -> `Instance`
name_as_list = Module.split(module) """
@spec convert_to_strings([map()]) :: [map()]
List.starts_with?(name_as_list, ["Pleroma", "Upload", "Filter"]) def convert_to_strings(descriptions) do
end) Enum.map(descriptions, &format_entity(&1))
end end
@spec mrf_list() :: [module()] defp format_entity(entity) do
def mrf_list do entity
{:ok, modules} = :application.get_key(:pleroma, :modules) |> format_key()
|> Map.put(:group, atom_to_string(entity[:group]))
Enum.filter(modules, fn module -> |> format_children()
name_as_list = Module.split(module)
List.starts_with?(name_as_list, ["Pleroma", "Web", "ActivityPub", "MRF"]) and
length(name_as_list) > 4
end)
end end
@spec richmedia_parsers() :: [module()] defp format_key(%{key: key} = entity) do
def richmedia_parsers do entity
{:ok, modules} = :application.get_key(:pleroma, :modules) |> Map.put(:key, atom_to_string(key))
|> Map.put(:label, entity[:label] || humanize(key))
Enum.filter(modules, fn module ->
name_as_list = Module.split(module)
List.starts_with?(name_as_list, ["Pleroma", "Web", "RichMedia", "Parsers"]) and
length(name_as_list) == 5
end)
end end
defp format_key(%{group: group} = entity) do
Map.put(entity, :label, entity[:label] || humanize(group))
end
defp format_key(entity), do: entity
defp format_children(%{children: children} = entity) do
Map.put(entity, :children, Enum.map(children, &format_child(&1)))
end
defp format_children(entity), do: entity
defp format_child(%{suggestions: suggestions} = entity) do
entity
|> Map.put(:suggestions, format_suggestions(suggestions))
|> format_key()
|> format_group()
|> format_children()
end
defp format_child(entity) do
entity
|> format_key()
|> format_group()
|> format_children()
end
defp format_group(%{group: group} = entity) do
Map.put(entity, :group, format_suggestion(group))
end
defp format_group(entity), do: entity
defp atom_to_string(entity) when is_binary(entity), do: entity
defp atom_to_string(entity) when is_atom(entity), do: inspect(entity)
defp humanize(entity) do
string = inspect(entity)
if String.starts_with?(string, ":"),
do: Phoenix.Naming.humanize(entity),
else: string
end
defp format_suggestions([]), do: []
defp format_suggestions([suggestion | tail]) do
[format_suggestion(suggestion) | format_suggestions(tail)]
end
defp format_suggestion(entity) when is_atom(entity) do
atom_to_string(entity)
end
defp format_suggestion([head | tail] = entity) when is_list(entity) do
[format_suggestion(head) | format_suggestions(tail)]
end
defp format_suggestion(entity) when is_tuple(entity) do
format_suggestions(Tuple.to_list(entity)) |> List.to_tuple()
end
defp format_suggestion(entity), do: entity
end end
defimpl Jason.Encoder, for: Tuple do defimpl Jason.Encoder, for: Tuple do
def encode(tuple, opts) do def encode(tuple, opts), do: Jason.Encode.list(Tuple.to_list(tuple), opts)
Jason.Encode.list(Tuple.to_list(tuple), opts)
end
end end
defimpl Jason.Encoder, for: [Regex, Function] do defimpl Jason.Encoder, for: [Regex, Function] do
def encode(term, opts) do def encode(term, opts), do: Jason.Encode.string(inspect(term), opts)
Jason.Encode.string(inspect(term), opts)
end
end end
defimpl String.Chars, for: Regex do defimpl String.Chars, for: Regex do
def to_string(term) do def to_string(term), do: inspect(term)
inspect(term)
end
end end

View File

@ -3,18 +3,22 @@ defmodule Pleroma.Docs.JSON do
@spec process(keyword()) :: {:ok, String.t()} @spec process(keyword()) :: {:ok, String.t()}
def process(descriptions) do def process(descriptions) do
config_path = "docs/generate_config.json" with path <- "docs/generated_config.json",
{:ok, file} <- File.open(path, [:write, :utf8]),
with {:ok, file} <- File.open(config_path, [:write, :utf8]), formatted_descriptions <-
json <- generate_json(descriptions), Pleroma.Docs.Generator.convert_to_strings(descriptions),
json <- Jason.encode!(formatted_descriptions),
:ok <- IO.write(file, json), :ok <- IO.write(file, json),
:ok <- File.close(file) do :ok <- File.close(file) do
{:ok, config_path} {:ok, path}
end end
end end
@spec generate_json([keyword()]) :: String.t() def compile do
def generate_json(descriptions) do with config <- Pleroma.Config.Loader.load("config/description.exs") do
Jason.encode!(descriptions) config[:pleroma][:config_description]
|> Pleroma.Docs.Generator.convert_to_strings()
|> Jason.encode!()
end
end end
end end

View File

@ -312,19 +312,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Map.put("content", emoji) |> Map.put("content", emoji)
end end
@spec update_element_in_object(String.t(), list(any), Object.t()) :: @spec update_element_in_object(String.t(), list(any), Object.t(), integer() | nil) ::
{:ok, Object.t()} | {:error, Ecto.Changeset.t()} {:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def update_element_in_object(property, element, object) do def update_element_in_object(property, element, object, count \\ nil) do
length = length =
if is_map(element) do count ||
element length(element)
|> Map.values()
|> List.flatten()
|> length()
else
element
|> length()
end
data = data =
Map.merge( Map.merge(
@ -344,29 +337,52 @@ defmodule Pleroma.Web.ActivityPub.Utils do
%Activity{data: %{"content" => emoji, "actor" => actor}}, %Activity{data: %{"content" => emoji, "actor" => actor}},
object object
) do ) do
reactions = object.data["reactions"] || %{} reactions = object.data["reactions"] || []
emoji_actors = reactions[emoji] || []
new_emoji_actors = [actor | emoji_actors] |> Enum.uniq() new_reactions =
new_reactions = Map.put(reactions, emoji, new_emoji_actors) case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
update_element_in_object("reaction", new_reactions, object) nil ->
reactions ++ [[emoji, [actor]]]
index ->
List.update_at(
reactions,
index,
fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
)
end
count = emoji_count(new_reactions)
update_element_in_object("reaction", new_reactions, object, count)
end
def emoji_count(reactions_list) do
Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
end end
def remove_emoji_reaction_from_object( def remove_emoji_reaction_from_object(
%Activity{data: %{"content" => emoji, "actor" => actor}}, %Activity{data: %{"content" => emoji, "actor" => actor}},
object object
) do ) do
reactions = object.data["reactions"] || %{} reactions = object.data["reactions"] || []
emoji_actors = reactions[emoji] || []
new_emoji_actors = List.delete(emoji_actors, actor)
new_reactions = new_reactions =
if new_emoji_actors == [] do case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
Map.delete(reactions, emoji) nil ->
else reactions
Map.put(reactions, emoji, new_emoji_actors)
index ->
List.update_at(
reactions,
index,
fn [emoji, users] -> [emoji, List.delete(users, actor)] end
)
|> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
end end
update_element_in_object("reaction", new_reactions, object) count = emoji_count(new_reactions)
update_element_in_object("reaction", new_reactions, object, count)
end end
@spec add_like_to_object(Activity.t(), Object.t()) :: @spec add_like_to_object(Activity.t(), Object.t()) ::

View File

@ -4,7 +4,11 @@
defmodule Pleroma.Web.AdminAPI.AdminAPIController do defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.ConfigDB
alias Pleroma.ModerationLog alias Pleroma.ModerationLog
alias Pleroma.Plugs.OAuthScopesPlug alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.ReportNote alias Pleroma.ReportNote
@ -14,7 +18,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.AdminAPI.Config
alias Pleroma.Web.AdminAPI.ConfigView alias Pleroma.Web.AdminAPI.ConfigView
alias Pleroma.Web.AdminAPI.ModerationLogView alias Pleroma.Web.AdminAPI.ModerationLogView
alias Pleroma.Web.AdminAPI.Report alias Pleroma.Web.AdminAPI.Report
@ -25,10 +28,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.Router alias Pleroma.Web.Router
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
require Logger require Logger
@descriptions_json Pleroma.Docs.JSON.compile()
@users_page_size 50
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["read:accounts"], admin: true} %{scopes: ["read:accounts"], admin: true}
@ -93,7 +97,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["read"], admin: true} %{scopes: ["read"], admin: true}
when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] when action in [:config_show, :migrate_from_db, :list_log]
) )
plug( plug(
@ -102,8 +106,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
when action == :config_update when action == :config_update
) )
@users_page_size 50
action_fallback(:errors) action_fallback(:errors)
def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
@ -785,49 +787,132 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> render("index.json", %{log: log}) |> render("index.json", %{log: log})
end end
def migrate_to_db(conn, _params) do def config_descriptions(conn, _params) do
Mix.Tasks.Pleroma.Config.run(["migrate_to_db"]) conn
json(conn, %{}) |> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(200, @descriptions_json)
end end
def migrate_from_db(conn, _params) do def migrate_from_db(conn, _params) do
Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"]) with :ok <- configurable_from_database(conn) do
json(conn, %{}) Mix.Tasks.Pleroma.Config.run([
"migrate_from_db",
"--env",
to_string(Pleroma.Config.get(:env)),
"-d"
])
json(conn, %{})
end
end
def config_show(conn, %{"only_db" => true}) do
with :ok <- configurable_from_database(conn) do
configs = Pleroma.Repo.all(ConfigDB)
if configs == [] do
errors(
conn,
{:error, "To use configuration from database migrate your settings to database."}
)
else
conn
|> put_view(ConfigView)
|> render("index.json", %{configs: configs})
end
end
end end
def config_show(conn, _params) do def config_show(conn, _params) do
configs = Pleroma.Repo.all(Config) with :ok <- configurable_from_database(conn) do
configs = ConfigDB.get_all_as_keyword()
conn if configs == [] do
|> put_view(ConfigView) errors(
|> render("index.json", %{configs: configs}) conn,
{:error, "To use configuration from database migrate your settings to database."}
)
else
merged =
Pleroma.Config.Holder.config()
|> ConfigDB.merge(configs)
|> Enum.map(fn {group, values} ->
Enum.map(values, fn {key, value} ->
db =
if configs[group][key] do
ConfigDB.get_db_keys(configs[group][key], key)
end
db_value = configs[group][key]
merged_value =
if !is_nil(db_value) and Keyword.keyword?(db_value) and
ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
ConfigDB.merge_group(group, key, value, db_value)
else
value
end
setting = %{
group: ConfigDB.convert(group),
key: ConfigDB.convert(key),
value: ConfigDB.convert(merged_value)
}
if db, do: Map.put(setting, :db, db), else: setting
end)
end)
|> List.flatten()
json(conn, %{configs: merged})
end
end
end end
def config_update(conn, %{"configs" => configs}) do def config_update(conn, %{"configs" => configs}) do
updated = with :ok <- configurable_from_database(conn) do
if Pleroma.Config.get([:instance, :dynamic_configuration]) do {_errors, results} =
updated = Enum.map(configs, fn
Enum.map(configs, fn %{"group" => group, "key" => key, "delete" => true} = params ->
%{"group" => group, "key" => key, "delete" => "true"} = params -> ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
{:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]})
config
%{"group" => group, "key" => key, "value" => value} -> %{"group" => group, "key" => key, "value" => value} ->
{:ok, config} = Config.update_or_create(%{group: group, key: key, value: value}) ConfigDB.update_or_create(%{group: group, key: key, value: value})
config end)
end) |> Enum.split_with(fn result -> elem(result, 0) == :error end)
|> Enum.reject(&is_nil(&1))
Pleroma.Config.TransferTask.load_and_update_env() {deleted, updated} =
Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"]) results
updated |> Enum.map(fn {:ok, config} ->
else Map.put(config, :db, ConfigDB.get_db_keys(config))
[] end)
end |> Enum.split_with(fn config ->
Ecto.get_meta(config, :state) == :deleted
end)
conn Pleroma.Config.TransferTask.load_and_update_env(deleted)
|> put_view(ConfigView)
|> render("index.json", %{configs: updated}) Mix.Tasks.Pleroma.Config.run([
"migrate_from_db",
"--env",
to_string(Pleroma.Config.get(:env))
])
conn
|> put_view(ConfigView)
|> render("index.json", %{configs: updated})
end
end
defp configurable_from_database(conn) do
if Pleroma.Config.get(:configurable_from_database) do
:ok
else
errors(
conn,
{:error, "To use this endpoint you need to enable configuration from database."}
)
end
end end
def reload_emoji(conn, _params) do def reload_emoji(conn, _params) do

View File

@ -1,182 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.Config do
use Ecto.Schema
import Ecto.Changeset
import Pleroma.Web.Gettext
alias __MODULE__
alias Pleroma.Repo
@type t :: %__MODULE__{}
schema "config" do
field(:key, :string)
field(:group, :string)
field(:value, :binary)
timestamps()
end
@spec get_by_params(map()) :: Config.t() | nil
def get_by_params(params), do: Repo.get_by(Config, params)
@spec changeset(Config.t(), map()) :: Changeset.t()
def changeset(config, params \\ %{}) do
config
|> cast(params, [:key, :group, :value])
|> validate_required([:key, :group, :value])
|> unique_constraint(:key, name: :config_group_key_index)
end
@spec create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def create(params) do
%Config{}
|> changeset(Map.put(params, :value, transform(params[:value])))
|> Repo.insert()
end
@spec update(Config.t(), map()) :: {:ok, Config} | {:error, Changeset.t()}
def update(%Config{} = config, %{value: value}) do
config
|> change(value: transform(value))
|> Repo.update()
end
@spec update_or_create(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def update_or_create(params) do
with %Config{} = config <- Config.get_by_params(Map.take(params, [:group, :key])) do
Config.update(config, params)
else
nil -> Config.create(params)
end
end
@spec delete(map()) :: {:ok, Config.t()} | {:error, Changeset.t()}
def delete(params) do
with %Config{} = config <- Config.get_by_params(Map.delete(params, :subkeys)) do
if params[:subkeys] do
updated_value =
Keyword.drop(
:erlang.binary_to_term(config.value),
Enum.map(params[:subkeys], &do_transform_string(&1))
)
Config.update(config, %{value: updated_value})
else
Repo.delete(config)
{:ok, nil}
end
else
nil ->
err =
dgettext("errors", "Config with params %{params} not found", params: inspect(params))
{:error, err}
end
end
@spec from_binary(binary()) :: term()
def from_binary(binary), do: :erlang.binary_to_term(binary)
@spec from_binary_with_convert(binary()) :: any()
def from_binary_with_convert(binary) do
from_binary(binary)
|> do_convert()
end
defp do_convert(entity) when is_list(entity) do
for v <- entity, into: [], do: do_convert(v)
end
defp do_convert(%Regex{} = entity), do: inspect(entity)
defp do_convert(entity) when is_map(entity) do
for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)}
end
defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]}
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
defp do_convert(entity) when is_tuple(entity),
do: %{"tuple" => do_convert(Tuple.to_list(entity))}
defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity),
do: entity
defp do_convert(entity) when is_atom(entity) do
string = to_string(entity)
if String.starts_with?(string, "Elixir."),
do: do_convert(string),
else: ":" <> string
end
defp do_convert("Elixir." <> module_name), do: module_name
defp do_convert(entity) when is_binary(entity), do: entity
@spec transform(any()) :: binary()
def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do
:erlang.term_to_binary(do_transform(entity))
end
def transform(entity), do: :erlang.term_to_binary(entity)
defp do_transform(%Regex{} = entity), do: entity
defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do
{dispatch_settings, []} = do_eval(entity)
{:dispatch, [dispatch_settings]}
end
defp do_transform(%{"tuple" => [":partial_chain", entity]}) do
{partial_chain, []} = do_eval(entity)
{:partial_chain, partial_chain}
end
defp do_transform(%{"tuple" => entity}) do
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
end
defp do_transform(entity) when is_map(entity) do
for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)}
end
defp do_transform(entity) when is_list(entity) do
for v <- entity, into: [], do: do_transform(v)
end
defp do_transform(entity) when is_binary(entity) do
String.trim(entity)
|> do_transform_string()
end
defp do_transform(entity), do: entity
defp do_transform_string("~r/" <> pattern) do
modificator = String.split(pattern, "/") |> List.last()
pattern = String.trim_trailing(pattern, "/" <> modificator)
case modificator do
"" -> ~r/#{pattern}/
"i" -> ~r/#{pattern}/i
"u" -> ~r/#{pattern}/u
"s" -> ~r/#{pattern}/s
end
end
defp do_transform_string(":" <> atom), do: String.to_atom(atom)
defp do_transform_string(value) do
if String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix"),
do: String.to_existing_atom("Elixir." <> value),
else: value
end
defp do_eval(entity) do
cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
Code.eval_string(cleaned_string, [], requires: [], macros: [])
end
end

View File

@ -12,10 +12,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do
end end
def render("show.json", %{config: config}) do def render("show.json", %{config: config}) do
%{ map = %{
key: config.key, key: config.key,
group: config.group, group: config.group,
value: Pleroma.Web.AdminAPI.Config.from_binary_with_convert(config.value) value: Pleroma.ConfigDB.from_binary_with_convert(config.value)
} }
if config.db != [] do
Map.put(map, :db, config.db)
else
map
end
end end
end end

View File

@ -255,12 +255,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
emoji_reactions = emoji_reactions =
with %{data: %{"reactions" => emoji_reactions}} <- object do with %{data: %{"reactions" => emoji_reactions}} <- object do
Enum.map(emoji_reactions, fn {emoji, users} -> Enum.map(emoji_reactions, fn [emoji, users] ->
{emoji, length(users)} [emoji, length(users)]
end) end)
|> Enum.into(%{})
else else
_ -> %{} _ -> []
end end
%{ %{

View File

@ -43,21 +43,21 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
%Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
Object.normalize(activity) do
reactions = reactions =
emoji_reactions emoji_reactions
|> Enum.map(fn {emoji, users} -> |> Enum.map(fn [emoji, users] ->
users = Enum.map(users, &User.get_cached_by_ap_id/1) users = Enum.map(users, &User.get_cached_by_ap_id/1)
{emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})}
end) end)
|> Enum.into(%{})
conn conn
|> json(reactions) |> json(reactions)
else else
_e -> _e ->
conn conn
|> json(%{}) |> json([])
end end
end end

View File

@ -195,7 +195,7 @@ defmodule Pleroma.Web.Router do
get("/config", AdminAPIController, :config_show) get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update) post("/config", AdminAPIController, :config_update)
get("/config/migrate_to_db", AdminAPIController, :migrate_to_db) get("/config/descriptions", AdminAPIController, :config_descriptions)
get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) get("/config/migrate_from_db", AdminAPIController, :migrate_from_db)
get("/moderation_log", AdminAPIController, :list_log) get("/moderation_log", AdminAPIController, :list_log)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{828: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))})}},[[828,0]]]); (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{895: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))})}},[[895,0]]]);
//# sourceMappingURL=embed.js.map //# sourceMappingURL=embed.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/core/embed.js"],"names":["window","addEventListener","e","data","setEmbedHeight","parent","postMessage","type","id","height","document","getElementsByTagName","scrollHeight","includes","readyState"],"mappings":"2EAEAA,OAAOC,iBAAiB,UAAW,SAAAC,GACjC,IAAMC,EAAOD,EAAEC,MAAQ,GAMvB,SAASC,IACPJ,OAAOK,OAAOC,YAAY,CACxBC,KAAM,YACNC,GAAIL,EAAKK,GACTC,OAAQC,SAASC,qBAAqB,QAAQ,GAAGC,cAChD,KATAZ,OAAOK,QAAwB,cAAdF,EAAKI,OAYvB,CAAC,cAAe,YAAYM,SAASH,SAASI,YAChDV,IAEAM,SAAST,iBAAiB,mBAAoBG","file":"core/embed.js","sourcesContent":["// This file will be loaded on embed pages, regardless of theme.\n\nwindow.addEventListener('message', e => {\n const data = e.data || {};\n\n if (!window.parent || data.type !== 'setHeight') {\n return;\n }\n\n function setEmbedHeight () {\n window.parent.postMessage({\n type: 'setHeight',\n id: data.id,\n height: document.getElementsByTagName('html')[0].scrollHeight,\n }, '*');\n };\n\n if (['interactive', 'complete'].includes(document.readyState)) {\n setEmbedHeight();\n } else {\n document.addEventListener('DOMContentLoaded', setEmbedHeight);\n }\n});\n"],"sourceRoot":""} {"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/core/embed.js"],"names":["window","addEventListener","e","data","setEmbedHeight","parent","postMessage","type","id","height","document","getElementsByTagName","scrollHeight","includes","readyState"],"mappings":"2EAEAA,OAAOC,iBAAiB,UAAW,SAAAC,GACjC,IAAMC,EAAOD,EAAEC,MAAQ,GAMvB,SAASC,IACPJ,OAAOK,OAAOC,YAAY,CACxBC,KAAM,YACNC,GAAIL,EAAKK,GACTC,OAAQC,SAASC,qBAAqB,QAAQ,GAAGC,cAChD,KATAZ,OAAOK,QAAwB,cAAdF,EAAKI,OAYvB,CAAC,cAAe,YAAYM,SAASH,SAASI,YAChDV,IAEAM,SAAST,iBAAiB,mBAAoBG,Q","file":"core/embed.js","sourcesContent":["// This file will be loaded on embed pages, regardless of theme.\n\nwindow.addEventListener('message', e => {\n const data = e.data || {};\n\n if (!window.parent || data.type !== 'setHeight') {\n return;\n }\n\n function setEmbedHeight () {\n window.parent.postMessage({\n type: 'setHeight',\n id: data.id,\n height: document.getElementsByTagName('html')[0].scrollHeight,\n }, '*');\n };\n\n if (['interactive', 'complete'].includes(document.readyState)) {\n setEmbedHeight();\n } else {\n document.addEventListener('DOMContentLoaded', setEmbedHeight);\n }\n});\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{829:function(n,o,w){"use strict";w.r(o);w(830)},830:function(n,o,w){}},[[829,0]]]); (window.webpackJsonp=window.webpackJsonp||[]).push([[8],{896:function(n,o,w){"use strict";w.r(o);w(897)},897:function(n,o,w){}},[[896,0]]]);
//# sourceMappingURL=mailer.js.map //# sourceMappingURL=mailer.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/core/mailer.js"],"names":["__webpack_require__","r","__webpack_exports__"],"mappings":"0FAAAA,EAAAC,EAAAC,GAAAF,EAAA","file":"core/mailer.js","sourcesContent":["import 'styles/mailer.scss';\n"],"sourceRoot":""} {"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/core/mailer.js"],"names":[],"mappings":"0FAAA,e","file":"core/mailer.js","sourcesContent":["import 'styles/mailer.scss';\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{672:function(n,r,i){"use strict";i.r(r);var o=i(915);i.d(r,"Picker",function(){return o.a});var c=i(899);i.d(r,"Emoji",function(){return c.a})}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[12],{718:function(n,r,i){"use strict";i.r(r);var o=i(996);i.d(r,"Picker",function(){return o.a});var c=i(972);i.d(r,"Emoji",function(){return c.a})}}]);
//# sourceMappingURL=emoji_picker.js.map //# sourceMappingURL=emoji_picker.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/mastodon/features/emoji/emoji_picker.js"],"names":["__webpack_require__","r","__webpack_exports__","emoji_mart_dist_es_components_picker_picker__WEBPACK_IMPORTED_MODULE_0__","d","emoji_mart_dist_es_components_emoji_emoji__WEBPACK_IMPORTED_MODULE_1__"],"mappings":"2FAAAA,EAAAC,EAAAC,GAAA,IAAAC,EAAAH,EAAA,KAAAA,EAAAI,EAAAF,EAAA,2BAAAC,EAAA,QAAAE,EAAAL,EAAA,KAAAA,EAAAI,EAAAF,EAAA,0BAAAG,EAAA","file":"emoji_picker.js","sourcesContent":["import Picker from 'emoji-mart/dist-es/components/picker/picker';\nimport Emoji from 'emoji-mart/dist-es/components/emoji/emoji';\n\nexport {\n Picker,\n Emoji,\n};\n"],"sourceRoot":""} {"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/mastodon/features/emoji/emoji_picker.js"],"names":[],"mappings":"2FAAA","file":"emoji_picker.js","sourcesContent":["import Picker from 'emoji-mart/dist-es/components/picker/picker';\nimport Emoji from 'emoji-mart/dist-es/components/emoji/emoji';\n\nexport {\n Picker,\n Emoji,\n};\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{678:function(t,a,e){"use strict";e.r(a),e.d(a,"default",function(){return _});var s,c,i,p=e(0),o=e(2),n=e(6),r=e(1),d=(e(3),e(21)),u=e(26),l=e.n(u),h=e(5),b=e.n(h),m=e(27),j=e(35),I=e(914),O=e(272),f=e(626),w=e(917),g=e(629),v=e(4),R=e(25),y=e(7),M=e(265),L=e(897),S=Object(v.List)(),_=Object(d.connect)(function(t,a){var e=a.params.accountId,s=a.withReplies,c=void 0!==s&&s,i=c?e+":with_replies":e;return{isAccount:!!t.getIn(["accounts",e]),statusIds:t.getIn(["timelines","account:"+i,"items"],S),featuredStatusIds:c?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=c=function(c){function t(){for(var a,t=arguments.length,e=new Array(t),s=0;s<t;s++)e[s]=arguments[s];return a=c.call.apply(c,[this].concat(e))||this,Object(r.a)(Object(o.a)(a),"handleLoadMore",function(t){a.props.dispatch(Object(j.p)(a.props.params.accountId,{maxId:t,withReplies:a.props.withReplies}))}),a}Object(n.a)(t,c);var a=t.prototype;return a.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.n)(a)),this.props.dispatch(Object(j.p)(a,{withReplies:e}))},a.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.n)(t.params.accountId)),this.props.dispatch(Object(j.p)(t.params.accountId,{withReplies:t.params.withReplies})))},a.render=function(){var t=this.props,a=t.shouldUpdateScroll,e=t.statusIds,s=t.featuredStatusIds,c=t.isLoading,i=t.hasMore,o=t.blockedBy;if(!t.isAccount)return Object(p.a)(f.a,{},void 0,Object(p.a)(L.a,{}));if(!e&&c)return Object(p.a)(f.a,{},void 0,Object(p.a)(O.a,{}));var n=o?Object(p.a)(y.b,{id:"empty_column.account_unavailable",defaultMessage:"Profile unavailable"}):Object(p.a)(y.b,{id:"empty_column.account_timeline",defaultMessage:"No toots here!"});return Object(p.a)(f.a,{},void 0,Object(p.a)(g.a,{}),Object(p.a)(I.a,{prepend:Object(p.a)(w.a,{accountId:this.props.params.accountId}),alwaysPrepend:!0,scrollKey:"account_timeline",statusIds:o?S:e,featuredStatusIds:s,isLoading:c,hasMore:i,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:n}))},t}(R.a),Object(r.a)(c,"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}),s=i))||s}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[15],{725: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),d=(e(3),e(12)),u=e(18),l=e.n(u),h=e(5),b=e.n(h),m=e(26),j=e(35),I=e(995),O=e(294),f=e(663),w=e(998),g=e(666),v=e(4),R=e(19),y=e(6),M=e(283),L=e(970),S=Object(v.List)(),_=Object(d.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)(L.a,{}));if(!e&&o)return Object(c.a)(f.a,{},void 0,Object(c.a)(O.a,{}));var d=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:d,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}}]);
//# sourceMappingURL=account_timeline.js.map //# sourceMappingURL=account_timeline.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{685: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(6),d=a(1),u=a(56),l=a.n(u),b=(a(3),a(21)),p=a(7),h=a(25),f=a(26),j=a.n(f),O=a(5),g=a.n(O),M=a(272),k=a(626),m=a(634),v=a(895),y=a(361),w=a(893),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(n){function e(){for(var e,t=arguments.length,a=new Array(t),o=0;o<t;o++)a[o]=arguments[o];return e=n.call.apply(n,[this].concat(a))||this,Object(d.a)(Object(r.a)(e),"handleLoadMore",l()(function(){e.props.dispatch(Object(y.c)())},300,{leading:!0})),e}Object(i.a)(e,n);var t=e.prototype;return t.componentWillMount=function(){this.props.dispatch(Object(y.d)())},t.render=function(){var e=this.props,t=e.intl,a=e.accountIds,o=e.shouldUpdateScroll,n=e.hasMore;if(!a)return Object(s.a)(k.a,{},void 0,Object(s.a)(M.a,{}));var c=Object(s.a)(p.b,{id:"empty_column.blocks",defaultMessage:"You haven't blocked any users yet."});return Object(s.a)(k.a,{icon:"ban",heading:t.formatMessage(I.heading)},void 0,Object(s.a)(m.a,{}),Object(s.a)(w.a,{scrollKey:"blocks",onLoadMore:this.handleLoadMore,hasMore:n,shouldUpdateScroll:o,emptyMessage:c},void 0,a.map(function(e){return Object(s.a)(v.a,{id:e},e)})))},e}(h.a),Object(d.a)(n,"propTypes",{params:g.a.object.isRequired,dispatch:g.a.func.isRequired,shouldUpdateScroll:g.a.func,accountIds:j.a.list,hasMore:g.a.bool,intl:g.a.object.isRequired}),o=c))||o)||o}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[16],{732: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(63),d=o.n(l),b=(o(3),o(12)),p=o(6),h=o(19),f=o(18),j=o.n(f),O=o(5),m=o.n(O),g=o(294),M=o(663),k=o(670),v=o(966),y=o(220),w=o(964),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}}]);
//# sourceMappingURL=blocks.js.map //# sourceMappingURL=blocks.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/mastodon/features/blocks/index.js"],"names":["messages","defineMessages","heading","id","defaultMessage","Blocks","connect","state","accountIds","getIn","hasMore","injectIntl","lodash_debounce__WEBPACK_IMPORTED_MODULE_4___default","_this","props","dispatch","expandBlocks","leading","componentWillMount","this","fetchBlocks","render","_this$props","intl","shouldUpdateScroll","Object","_babel_runtime_helpers_esm_jsx__WEBPACK_IMPORTED_MODULE_0__","_ui_components_column__WEBPACK_IMPORTED_MODULE_12__","_components_loading_indicator__WEBPACK_IMPORTED_MODULE_11__","emptyMessage","react_intl__WEBPACK_IMPORTED_MODULE_7__","icon","formatMessage","_components_column_back_button_slim__WEBPACK_IMPORTED_MODULE_13__","_components_scrollable_list__WEBPACK_IMPORTED_MODULE_16__","scrollKey","onLoadMore","handleLoadMore","map","_containers_account_container__WEBPACK_IMPORTED_MODULE_14__","ImmutablePureComponent","params","PropTypes","object","isRequired","func","ImmutablePropTypes","list","bool"],"mappings":"oTAcMA,EAAWC,YAAe,CAC9BC,QAAO,CAAAC,GAAA,gBAAAC,eAAA,mBAUHC,EAFUC,kBALQ,SAAAC,GAAK,MAAK,CAChCC,WAAYD,EAAME,MAAM,CAAC,aAAc,SAAU,UACjDC,UAAWH,EAAME,MAAM,CAAC,aAAc,SAAU,cAIjDE,gNAgBkBC,IAAS,WACxBC,EAAKC,MAAMC,SAASC,gBACnB,IAAK,CAAEC,SAAS,mDANnBC,mBAAA,WACEC,KAAKL,MAAMC,SAASK,kBAOtBC,OAAA,WAAU,IAAAC,EACkDH,KAAKL,MAAvDS,EADAD,EACAC,KAAMf,EADNc,EACMd,WAAYgB,EADlBF,EACkBE,mBAAoBd,EADtCY,EACsCZ,QAE9C,IAAKF,EACH,OACEiB,OAAAC,EAAA,EAAAD,CAACE,EAAA,EAAD,UACEF,OAAAC,EAAA,EAAAD,CAACG,EAAA,EAAD,KAKN,IAAMC,EAAeJ,OAAAC,EAAA,EAAAD,CAACK,EAAA,EAAD,CAAkB3B,GAAG,sBAAsBC,eAAe,uCAE/E,OACEqB,OAAAC,EAAA,EAAAD,CAACE,EAAA,EAAD,CAAQI,KAAK,MAAM7B,QAASqB,EAAKS,cAAchC,EAASE,eAAxD,EACEuB,OAAAC,EAAA,EAAAD,CAACQ,EAAA,EAAD,IACAR,OAAAC,EAAA,EAAAD,CAACS,EAAA,EAAD,CACEC,UAAU,SACVC,WAAYjB,KAAKkB,eACjB3B,QAASA,EACTc,mBAAoBA,EACpBK,aAAcA,QALhB,EAOGrB,EAAW8B,IAAI,SAAAnC,GAAE,OAChBsB,OAAAC,EAAA,EAAAD,CAACc,EAAA,EAAD,CAA2BpC,GAAIA,GAARA,WA3CdqC,+BAEA,CACjBC,OAAQC,IAAUC,OAAOC,WACzB7B,SAAU2B,IAAUG,KAAKD,WACzBpB,mBAAoBkB,IAAUG,KAC9BrC,WAAYsC,IAAmBC,KAC/BrC,QAASgC,IAAUM,KACnBzB,KAAMmB,IAAUC,OAAOC","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 };\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 } = 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 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 >\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":"oTAcMA,EAAWC,YAAe,CAC9BC,QAAQ,CAAD,qDAUHC,EAFUC,kBALQ,SAAAC,GAAK,MAAK,CAChCC,WAAYD,EAAME,MAAM,CAAC,aAAc,SAAU,UACjDC,UAAWH,EAAME,MAAM,CAAC,aAAc,SAAU,W,GAIjDE,a,mMAiBkB,IAAS,WACxB,EAAKC,MAAMC,SAASC,gBACnB,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,IAAI,SAAAR,GAAE,OAChB,YAAC,IAAD,CAA2BA,GAAIA,GAARA,Q,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":""}

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{715:function(e,t,n){"use strict";n.r(t);var o,i,c,d=n(0),a=n(2),l=n(6),s=n(1),r=n(3),u=n.n(r),m=n(21),p=n(7),h=n(5),b=n.n(h),y=n(904),f=n(633),j=n(628),M=n(35),O=n(222),g=n(987),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&&0<=i?o.get(i).get("params"):e.getIn(["settings","community"])}},function(n,e){var o=e.columnId;return{onChange:function(e,t){n(o?Object(O.f)(o,e,t):Object(v.c)(["community"].concat(e),t))}}})(g.a),C=n(635);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.onlyMedia,o=t.columnId,i=o,c=e.getIn(["settings","columns"]),a=c.findIndex(function(e){return e.get("uuid")===i});return{hasUnread:0<e.getIn(["timelines","community"+(n?":media":""),"unread"]),onlyMedia:o&&0<=a?c.get(a).getIn(["params","other","onlyMedia"]):e.getIn(["settings","community","other","onlyMedia"])}})(o=Object(p.g)((c=i=function(o){function e(){for(var i,e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return i=o.call.apply(o,[this].concat(t))||this,Object(s.a)(Object(a.a)(i),"handlePin",function(){var e=i.props,t=e.columnId,n=e.dispatch,o=e.onlyMedia;n(t?Object(O.h)(t):Object(O.e)("COMMUNITY",{other:{onlyMedia:o}}))}),Object(s.a)(Object(a.a)(i),"handleMove",function(e){var t=i.props,n=t.columnId;(0,t.dispatch)(Object(O.g)(n,e))}),Object(s.a)(Object(a.a)(i),"handleHeaderClick",function(){i.column.scrollTop()}),Object(s.a)(Object(a.a)(i),"setRef",function(e){i.column=e}),Object(s.a)(Object(a.a)(i),"handleLoadMore",function(e){var t=i.props,n=t.dispatch,o=t.onlyMedia;n(Object(M.q)({maxId:e,onlyMedia:o}))}),i}Object(l.a)(e,o);var t=e.prototype;return t.componentDidMount=function(){var e=this.props,t=e.dispatch,n=e.onlyMedia;t(Object(M.q)({onlyMedia:n})),this.disconnect=t(Object(C.a)({onlyMedia:n}))},t.componentDidUpdate=function(e){if(e.onlyMedia!==this.props.onlyMedia){var t=this.props,n=t.dispatch,o=t.onlyMedia;this.disconnect(),n(Object(M.q)({onlyMedia:o})),this.disconnect=n(Object(C.a)({onlyMedia:o}))}},t.componentWillUnmount=function(){this.disconnect&&(this.disconnect(),this.disconnect=null)},t.render=function(){var e=this.props,t=e.intl,n=e.shouldUpdateScroll,o=e.hasUnread,i=e.columnId,c=e.multiColumn,a=e.onlyMedia,l=!!i;return u.a.createElement(f.a,{ref:this.setRef,label:t.formatMessage(w.title)},Object(d.a)(j.a,{icon:"users",active:o,title:t.formatMessage(w.title),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:l,multiColumn:c},void 0,Object(d.a)(I,{columnId:i})),Object(d.a)(y.a,{trackScroll:!l,scrollKey:"community_timeline-"+i,timelineId:"community"+(a?":media":""),onLoadMore:this.handleLoadMore,emptyMessage:Object(d.a)(p.b,{id:"empty_column.community",defaultMessage:"The local timeline is empty. Write something publicly to get the ball rolling!"}),shouldUpdateScroll:n}))},e}(u.a.PureComponent),Object(s.a)(i,"contextTypes",{router:b.a.object}),Object(s.a)(i,"defaultProps",{onlyMedia:!1}),o=c))||o)||o}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[17],{766:function(e,t,n){"use strict";n.r(t);var o,i,c,a=n(0),l=n(2),d=n(7),s=n(1),r=n(3),u=n.n(r),m=n(12),p=n(6),h=n(5),b=n.n(h),y=n(977),f=n(669),j=n(665),M=n(35),O=n(245),g=n(1092),I=n(72),v=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(O.f)(n,t,o):Object(I.c)(["community"].concat(t),o))}}})(g.a),C=n(672);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.onlyMedia,o=t.columnId,i=o,c=e.getIn(["settings","columns"]),a=c.findIndex(function(e){return e.get("uuid")===i}),l=e.getIn(["timelines","community"+(n?":media":"")]);return{hasUnread:!!l&&(l.get("unread")>0||l.get("pendingItems").size>0),onlyMedia:o&&a>=0?c.get(a).getIn(["params","other","onlyMedia"]):e.getIn(["settings","community","other","onlyMedia"])}})(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(s.a)(Object(l.a)(t),"handlePin",function(){var e=t.props,n=e.columnId,o=e.dispatch,i=e.onlyMedia;o(n?Object(O.h)(n):Object(O.e)("COMMUNITY",{other:{onlyMedia:i}}))}),Object(s.a)(Object(l.a)(t),"handleMove",function(e){var n=t.props,o=n.columnId;(0,n.dispatch)(Object(O.g)(o,e))}),Object(s.a)(Object(l.a)(t),"handleHeaderClick",function(){t.column.scrollTop()}),Object(s.a)(Object(l.a)(t),"setRef",function(e){t.column=e}),Object(s.a)(Object(l.a)(t),"handleLoadMore",function(e){var n=t.props,o=n.dispatch,i=n.onlyMedia;o(Object(M.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(M.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(M.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(f.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)(v,{columnId:i})),Object(a.a)(y.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(s.a)(i,"contextTypes",{router:b.a.object}),Object(s.a)(i,"defaultProps",{onlyMedia:!1}),o=c))||o)||o}}]);
//# sourceMappingURL=community_timeline.js.map //# sourceMappingURL=community_timeline.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{711:function(n,e,o){"use strict";o.r(e);var a,t,i,c,r,s,d=o(0),l=o(2),u=o(6),m=o(1),b=o(56),f=o.n(b),p=(o(3),o(21)),j=o(7),O=o(25),h=o(5),g=o.n(h),k=o(26),v=o.n(k),M=o(272),y=o(626),_=o(634),w=o(187),D=o(67),U=Object(j.f)({unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unhide {domain}"}}),R=Object(j.g)((i=t=function(t){function n(){for(var n,e=arguments.length,o=new Array(e),a=0;a<e;a++)o[a]=arguments[a];return n=t.call.apply(t,[this].concat(o))||this,Object(m.a)(Object(l.a)(n),"handleDomainUnblock",function(){n.props.onUnblockDomain(n.props.domain)}),n}return Object(u.a)(n,t),n.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)(D.a,{active:!0,icon:"unlock",title:o.formatMessage(U.unblockDomain,{domain:e}),onClick:this.handleDomainUnblock}))))},n}(O.a),Object(m.a)(t,"propTypes",{domain:g.a.string,onUnblockDomain:g.a.func.isRequired,intl:g.a.object.isRequired}),a=i))||a,q=o(57),C=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(e,n){var o=n.intl;return{onBlockDomain:function(n){e(Object(q.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,n)}}),confirm:o.formatMessage(C.blockDomainConfirm),onConfirm:function(){return e(Object(w.e)(n))}}))},onUnblockDomain:function(n){e(Object(w.h)(n))}}})(R)),I=o(893);o.d(e,"default",function(){return A});var S=Object(j.f)({heading:{id:"column.domain_blocks",defaultMessage:"Hidden domains"},unblockDomain:{id:"account.unblock_domain",defaultMessage:"Unhide {domain}"}}),A=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(t){function n(){for(var n,e=arguments.length,o=new Array(e),a=0;a<e;a++)o[a]=arguments[a];return n=t.call.apply(t,[this].concat(o))||this,Object(m.a)(Object(l.a)(n),"handleLoadMore",f()(function(){n.props.dispatch(Object(w.f)())},300,{leading:!0})),n}Object(u.a)(n,t);var e=n.prototype;return e.componentWillMount=function(){this.props.dispatch(Object(w.g)())},e.render=function(){var n=this.props,e=n.intl,o=n.domains,a=n.shouldUpdateScroll,t=n.hasMore;if(!o)return Object(d.a)(y.a,{},void 0,Object(d.a)(M.a,{}));var i=Object(d.a)(j.b,{id:"empty_column.domain_blocks",defaultMessage:"There are no hidden domains yet."});return Object(d.a)(y.a,{icon:"minus-circle",heading:e.formatMessage(S.heading)},void 0,Object(d.a)(_.a,{}),Object(d.a)(I.a,{scrollKey:"domain_blocks",onLoadMore:this.handleLoadMore,hasMore:t,shouldUpdateScroll:a,emptyMessage:i},void 0,o.map(function(n){return Object(d.a)(N,{domain:n},n)})))},n}(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}),c=s))||c)||c}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[21],{758: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(63),f=o.n(b),p=(o(3),o(12)),j=o(6),O=o(19),h=o(5),g=o.n(h),k=o(18),v=o.n(k),M=o(294),y=o(663),_=o(670),D=o(81),w=o(51),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(964);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}}]);
//# sourceMappingURL=domain_blocks.js.map //# sourceMappingURL=domain_blocks.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{684:function(t,e,a){"use strict";a.r(e),a.d(e,"default",function(){return C});var o,n,s,r=a(0),i=a(2),c=a(6),u=a(1),l=a(56),d=a.n(l),h=a(3),p=a.n(h),f=a(21),b=a(5),j=a.n(b),O=a(26),g=a.n(O),m=a(190),v=a(626),M=a(628),I=a(222),w=a(914),y=a(7),L=a(25),k=Object(y.f)({heading:{id:"column.favourites",defaultMessage:"Favourites"}}),C=Object(f.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(n){function t(){for(var o,t=arguments.length,e=new Array(t),a=0;a<t;a++)e[a]=arguments[a];return o=n.call.apply(n,[this].concat(e))||this,Object(u.a)(Object(i.a)(o),"handlePin",function(){var t=o.props,e=t.columnId,a=t.dispatch;a(e?Object(I.h)(e):Object(I.e)("FAVOURITES",{}))}),Object(u.a)(Object(i.a)(o),"handleMove",function(t){var e=o.props,a=e.columnId;(0,e.dispatch)(Object(I.g)(a,t))}),Object(u.a)(Object(i.a)(o),"handleHeaderClick",function(){o.column.scrollTop()}),Object(u.a)(Object(i.a)(o),"setRef",function(t){o.column=t}),Object(u.a)(Object(i.a)(o),"handleLoadMore",d()(function(){o.props.dispatch(Object(m.g)())},300,{leading:!0})),o}Object(c.a)(t,n);var e=t.prototype;return e.componentWillMount=function(){this.props.dispatch(Object(m.h)())},e.render=function(){var t=this.props,e=t.intl,a=t.shouldUpdateScroll,o=t.statusIds,n=t.columnId,s=t.multiColumn,i=t.hasMore,c=t.isLoading,u=!!n,l=Object(r.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,{ref:this.setRef,label:e.formatMessage(k.heading)},Object(r.a)(M.a,{icon:"star",title:e.formatMessage(k.heading),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:u,multiColumn:s,showBackButton:!0}),Object(r.a)(w.a,{trackScroll:!u,statusIds:o,scrollKey:"favourited_statuses-"+n,hasMore:i,isLoading:c,onLoadMore:this.handleLoadMore,shouldUpdateScroll:a,emptyMessage:l}))},t}(L.a),Object(u.a)(n,"propTypes",{dispatch:j.a.func.isRequired,shouldUpdateScroll:j.a.func,statusIds:g.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([[22],{731: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(63),d=a.n(r),h=a(3),p=a.n(h),b=a(12),f=a(5),j=a.n(f),O=a(18),m=a.n(O),g=a(203),v=a(663),M=a(665),I=a(245),w=a(995),y=a(6),L=a(19),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}}]);
//# sourceMappingURL=favourited_statuses.js.map //# sourceMappingURL=favourited_statuses.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{682:function(t,a,e){"use strict";e.r(a),e.d(a,"default",function(){return y});var s,o,n,r=e(0),c=e(6),i=e(1),u=(e(3),e(21)),p=e(25),d=e(5),l=e.n(d),h=e(26),f=e.n(h),b=e(272),m=e(58),j=e(7),v=e(895),O=e(626),I=e(629),w=e(893),y=Object(u.connect)(function(t,a){return{accountIds:t.getIn(["user_lists","favourited_by",a.params.statusId])}})((n=o=function(t){function a(){return t.apply(this,arguments)||this}Object(c.a)(a,t);var e=a.prototype;return e.componentWillMount=function(){this.props.dispatch(Object(m.l)(this.props.params.statusId))},e.componentWillReceiveProps=function(t){t.params.statusId!==this.props.params.statusId&&t.params.statusId&&this.props.dispatch(Object(m.l)(t.params.statusId))},e.render=function(){var t=this.props,a=t.shouldUpdateScroll,e=t.accountIds;if(!e)return Object(r.a)(O.a,{},void 0,Object(r.a)(b.a,{}));var s=Object(r.a)(j.b,{id:"empty_column.favourites",defaultMessage:"No one has favourited this toot yet. When someone does, they will show up here."});return Object(r.a)(O.a,{},void 0,Object(r.a)(I.a,{}),Object(r.a)(w.a,{scrollKey:"favourites",shouldUpdateScroll:a,emptyMessage:s},void 0,e.map(function(t){return Object(r.a)(v.a,{id:t,withNote:!1},t)})))},a}(p.a),Object(i.a)(o,"propTypes",{params:l.a.object.isRequired,dispatch:l.a.func.isRequired,shouldUpdateScroll:l.a.func,accountIds:f.a.list}),s=n))||s}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[23],{729:function(t,a,s){"use strict";s.r(a),s.d(a,"default",function(){return y});var e,o,n,u=s(0),r=s(7),c=s(1),i=(s(3),s(12)),p=s(19),d=s(5),l=s.n(d),h=s(18),m=s.n(h),b=s(294),f=s(66),j=s(6),v=s(966),O=s(663),I=s(666),w=s(964),y=Object(i.connect)(function(t,a){return{accountIds:t.getIn(["user_lists","favourited_by",a.params.statusId])}})((n=o=function(t){function a(){return t.apply(this,arguments)||this}Object(r.a)(a,t);var s=a.prototype;return s.componentWillMount=function(){this.props.accountIds||this.props.dispatch(Object(f.l)(this.props.params.statusId))},s.componentWillReceiveProps=function(t){t.params.statusId!==this.props.params.statusId&&t.params.statusId&&this.props.dispatch(Object(f.l)(t.params.statusId))},s.render=function(){var t=this.props,a=t.shouldUpdateScroll,s=t.accountIds,e=t.multiColumn;if(!s)return Object(u.a)(O.a,{},void 0,Object(u.a)(b.a,{}));var o=Object(u.a)(j.b,{id:"empty_column.favourites",defaultMessage:"No one has favourited this toot yet. When someone does, they will show up here."});return Object(u.a)(O.a,{},void 0,Object(u.a)(I.a,{multiColumn:e}),Object(u.a)(w.a,{scrollKey:"favourites",shouldUpdateScroll:a,emptyMessage:o,bindToDocument:!e},void 0,s.map(function(t){return Object(u.a)(v.a,{id:t,withNote:!1},t)})))},a}(p.a),Object(c.a)(o,"propTypes",{params:l.a.object.isRequired,dispatch:l.a.func.isRequired,shouldUpdateScroll:l.a.func,accountIds:m.a.list,multiColumn:l.a.bool}),e=n))||e}}]);
//# sourceMappingURL=favourites.js.map //# sourceMappingURL=favourites.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/mastodon/features/favourites/index.js"],"names":["Favourites","connect","state","props","accountIds","getIn","params","statusId","componentWillMount","this","dispatch","fetchFavourites","componentWillReceiveProps","nextProps","render","_this$props","shouldUpdateScroll","Object","_babel_runtime_helpers_esm_jsx__WEBPACK_IMPORTED_MODULE_0__","_ui_components_column__WEBPACK_IMPORTED_MODULE_12__","_components_loading_indicator__WEBPACK_IMPORTED_MODULE_8__","emptyMessage","react_intl__WEBPACK_IMPORTED_MODULE_10__","id","defaultMessage","_components_column_back_button__WEBPACK_IMPORTED_MODULE_13__","_components_scrollable_list__WEBPACK_IMPORTED_MODULE_14__","scrollKey","map","_containers_account_container__WEBPACK_IMPORTED_MODULE_11__","withNote","ImmutablePureComponent","PropTypes","object","isRequired","func","ImmutablePropTypes","list"],"mappings":"2RAkBMA,EADUC,kBAJQ,SAACC,EAAOC,GAAR,MAAmB,CACzCC,WAAYF,EAAMG,MAAM,CAAC,aAAc,gBAAiBF,EAAMG,OAAOC,6HAarEC,mBAAA,WACEC,KAAKN,MAAMO,SAASC,YAAgBF,KAAKN,MAAMG,OAAOC,cAGxDK,0BAAA,SAA2BC,GACrBA,EAAUP,OAAOC,WAAaE,KAAKN,MAAMG,OAAOC,UAAYM,EAAUP,OAAOC,UAC/EE,KAAKN,MAAMO,SAASC,YAAgBE,EAAUP,OAAOC,cAIzDO,OAAA,WAAU,IAAAC,EACmCN,KAAKN,MAAxCa,EADAD,EACAC,mBAAoBZ,EADpBW,EACoBX,WAE5B,IAAKA,EACH,OACEa,OAAAC,EAAA,EAAAD,CAACE,EAAA,EAAD,UACEF,OAAAC,EAAA,EAAAD,CAACG,EAAA,EAAD,KAKN,IAAMC,EAAeJ,OAAAC,EAAA,EAAAD,CAACK,EAAA,EAAD,CAAkBC,GAAG,0BAA0BC,eAAe,oFAEnF,OACEP,OAAAC,EAAA,EAAAD,CAACE,EAAA,EAAD,UACEF,OAAAC,EAAA,EAAAD,CAACQ,EAAA,EAAD,IAEAR,OAAAC,EAAA,EAAAD,CAACS,EAAA,EAAD,CACEC,UAAU,aACVX,mBAAoBA,EACpBK,aAAcA,QAHhB,EAKGjB,EAAWwB,IAAI,SAAAL,GAAE,OAChBN,OAAAC,EAAA,EAAAD,CAACY,EAAA,EAAD,CAA2BN,GAAIA,EAAIO,UAAU,GAAtBP,WA1CVQ,+BAEJ,CACjBzB,OAAQ0B,IAAUC,OAAOC,WACzBxB,SAAUsB,IAAUG,KAAKD,WACzBlB,mBAAoBgB,IAAUG,KAC9B/B,WAAYgC,IAAmBC","file":"features/favourites.js","sourcesContent":["import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport { fetchFavourites } from '../../actions/interactions';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst mapStateToProps = (state, props) => ({\n accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),\n});\n\nexport default @connect(mapStateToProps)\nclass Favourites 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 };\n\n componentWillMount () {\n this.props.dispatch(fetchFavourites(this.props.params.statusId));\n }\n\n componentWillReceiveProps (nextProps) {\n if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {\n this.props.dispatch(fetchFavourites(nextProps.params.statusId));\n }\n }\n\n render () {\n const { shouldUpdateScroll, accountIds } = this.props;\n\n if (!accountIds) {\n return (\n <Column>\n <LoadingIndicator />\n </Column>\n );\n }\n\n const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />;\n\n return (\n <Column>\n <ColumnBackButton />\n\n <ScrollableList\n scrollKey='favourites'\n shouldUpdateScroll={shouldUpdateScroll}\n emptyMessage={emptyMessage}\n >\n {accountIds.map(id =>\n <AccountContainer key={id} id={id} withNote={false} />\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/favourites/index.js"],"names":["Favourites","connect","state","props","accountIds","getIn","params","statusId","componentWillMount","this","dispatch","fetchFavourites","componentWillReceiveProps","nextProps","render","shouldUpdateScroll","multiColumn","emptyMessage","id","defaultMessage","scrollKey","bindToDocument","map","withNote","ImmutablePureComponent","PropTypes","object","isRequired","func","ImmutablePropTypes","list","bool"],"mappings":"2RAkBMA,EADUC,kBAJQ,SAACC,EAAOC,GAAR,MAAmB,CACzCC,WAAYF,EAAMG,MAAM,CAAC,aAAc,gBAAiBF,EAAMG,OAAOC,a,gHAcrEC,mBAAA,WACOC,KAAKN,MAAMC,YACdK,KAAKN,MAAMO,SAASC,YAAgBF,KAAKN,MAAMG,OAAOC,Y,EAI1DK,0BAAA,SAA2BC,GACrBA,EAAUP,OAAOC,WAAaE,KAAKN,MAAMG,OAAOC,UAAYM,EAAUP,OAAOC,UAC/EE,KAAKN,MAAMO,SAASC,YAAgBE,EAAUP,OAAOC,Y,EAIzDO,OAAA,WAAW,IAAD,EACgDL,KAAKN,MAArDY,EADA,EACAA,mBAAoBX,EADpB,EACoBA,WAAYY,EADhC,EACgCA,YAExC,IAAKZ,EACH,OACE,YAAC,IAAD,UACE,YAAC,IAAD,KAKN,IAAMa,EAAe,YAAC,IAAD,CAAkBC,GAAG,0BAA0BC,eAAe,oFAEnF,OACE,YAAC,IAAD,UACE,YAAC,IAAD,CAAkBH,YAAaA,IAE/B,YAAC,IAAD,CACEI,UAAU,aACVL,mBAAoBA,EACpBE,aAAcA,EACdI,gBAAiBL,QAJnB,EAMGZ,EAAWkB,IAAI,SAAAJ,GAAE,OAChB,YAAC,IAAD,CAA2BA,GAAIA,EAAIK,UAAU,GAAtBL,Q,GA9CVM,K,0BAEJ,CACjBlB,OAAQmB,IAAUC,OAAOC,WACzBjB,SAAUe,IAAUG,KAAKD,WACzBZ,mBAAoBU,IAAUG,KAC9BxB,WAAYyB,IAAmBC,KAC/Bd,YAAaS,IAAUM,O","file":"features/favourites.js","sourcesContent":["import React from 'react';\nimport { connect } from 'react-redux';\nimport ImmutablePureComponent from 'react-immutable-pure-component';\nimport PropTypes from 'prop-types';\nimport ImmutablePropTypes from 'react-immutable-proptypes';\nimport LoadingIndicator from '../../components/loading_indicator';\nimport { fetchFavourites } from '../../actions/interactions';\nimport { FormattedMessage } from 'react-intl';\nimport AccountContainer from '../../containers/account_container';\nimport Column from '../ui/components/column';\nimport ColumnBackButton from '../../components/column_back_button';\nimport ScrollableList from '../../components/scrollable_list';\n\nconst mapStateToProps = (state, props) => ({\n accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),\n});\n\nexport default @connect(mapStateToProps)\nclass Favourites 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 multiColumn: PropTypes.bool,\n };\n\n componentWillMount () {\n if (!this.props.accountIds) {\n this.props.dispatch(fetchFavourites(this.props.params.statusId));\n }\n }\n\n componentWillReceiveProps (nextProps) {\n if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {\n this.props.dispatch(fetchFavourites(nextProps.params.statusId));\n }\n }\n\n render () {\n const { shouldUpdateScroll, accountIds, 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.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />;\n\n return (\n <Column>\n <ColumnBackButton multiColumn={multiColumn} />\n\n <ScrollableList\n scrollKey='favourites'\n shouldUpdateScroll={shouldUpdateScroll}\n emptyMessage={emptyMessage}\n bindToDocument={!multiColumn}\n >\n {accountIds.map(id =>\n <AccountContainer key={id} id={id} withNote={false} />\n )}\n </ScrollableList>\n </Column>\n );\n }\n\n}\n"],"sourceRoot":""}

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{710:function(e,t,a){"use strict";a.r(t);var o,c,n,i,r,s,u=a(0),l=a(2),d=a(6),j=a(1),p=a(56),b=a.n(p),f=(a(3),a(21)),h=a(7),O=a(25),v=a(5),_=a.n(v),m=a(26),g=a.n(m),w=a(272),M=a(626),q=a(634),y=a(200),z=a(379),R=a(194),N=a(195),I=a(67),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(j.a)(c,"propTypes",{account:g.a.map.isRequired,onAuthorize:_.a.func.isRequired,onReject:_.a.func.isRequired,intl:_.a.object.isRequired}),o=n))||o,L=a(27),S=Object(f.connect)(function(){var a=Object(y.d)();return function(e,t){return{account:a(e,t.id)}}},function(e,t){var a=t.id;return{onAuthorize:function(){e(Object(L.v)(a))},onReject:function(){e(Object(L.I)(a))}}})(A),T=a(893);a.d(t,"default",function(){return x});var U=Object(h.f)({heading:{id:"column.follow_requests",defaultMessage:"Follow requests"}}),x=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(c){function e(){for(var e,t=arguments.length,a=new Array(t),o=0;o<t;o++)a[o]=arguments[o];return e=c.call.apply(c,[this].concat(a))||this,Object(j.a)(Object(l.a)(e),"handleLoadMore",b()(function(){e.props.dispatch(Object(L.x)())},300,{leading:!0})),e}Object(d.a)(e,c);var t=e.prototype;return t.componentWillMount=function(){this.props.dispatch(Object(L.B)())},t.render=function(){var e=this.props,t=e.intl,a=e.shouldUpdateScroll,o=e.accountIds,c=e.hasMore;if(!o)return Object(u.a)(M.a,{},void 0,Object(u.a)(w.a,{}));var n=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,{icon:"users",heading:t.formatMessage(U.heading)},void 0,Object(u.a)(q.a,{}),Object(u.a)(T.a,{scrollKey:"follow_requests",onLoadMore:this.handleLoadMore,hasMore:c,shouldUpdateScroll:a,emptyMessage:n},void 0,o.map(function(e){return Object(u.a)(S,{id:e},e)})))},e}(O.a),Object(j.a)(r,"propTypes",{params:_.a.object.isRequired,dispatch:_.a.func.isRequired,shouldUpdateScroll:_.a.func,hasMore:_.a.bool,accountIds:g.a.list,intl:_.a.object.isRequired}),i=s))||i)||i}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[24],{757: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(63),p=a.n(j),f=(a(3),a(12)),h=a(6),O=a(19),m=a(5),v=a.n(m),_=a(18),g=a.n(_),w=a(294),M=a(663),q=a(670),y=a(204),z=a(286),R=a(107),N=a(116),I=a(51),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(26),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(964);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}}]);
//# sourceMappingURL=follow_requests.js.map //# sourceMappingURL=follow_requests.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{679:function(a,t,o){"use strict";o.r(t),o.d(t,"default",function(){return _});var c,e,s,n=o(0),r=o(2),p=o(6),i=o(1),u=o(56),d=o.n(u),l=(o(3),o(21)),b=o(25),h=o(5),f=o.n(h),j=o(26),m=o.n(j),I=o(272),O=o(27),y=o(7),w=o(895),v=o(626),M=o(917),g=o(629),k=o(893),A=o(897),_=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(e){function a(){for(var a,t=arguments.length,o=new Array(t),c=0;c<t;c++)o[c]=arguments[c];return a=e.call.apply(e,[this].concat(o))||this,Object(i.a)(Object(r.a)(a),"handleLoadMore",d()(function(){a.props.dispatch(Object(O.y)(a.props.params.accountId))},300,{leading:!0})),a}Object(p.a)(a,e);var t=a.prototype;return t.componentWillMount=function(){this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.C)(this.props.params.accountId))},t.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)))},t.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy;if(!a.isAccount)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 s=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,{}),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:s},void 0,e?[]:o.map(function(a){return Object(n.a)(w.a,{id:a,withNote:!1},a)})))},a}(b.a),Object(i.a)(e,"propTypes",{params:f.a.object.isRequired,dispatch:f.a.func.isRequired,shouldUpdateScroll:f.a.func,accountIds:m.a.list,hasMore:f.a.bool,blockedBy:f.a.bool,isAccount:f.a.bool}),c=s))||c}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[25],{726: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(63),d=o.n(u),l=(o(3),o(12)),b=o(19),h=o(5),m=o.n(h),f=o(18),j=o.n(f),I=o(294),O=o(26),y=o(6),w=o(966),v=o(663),M=o(998),g=o(666),k=o(964),A=o(970),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}}]);
//# sourceMappingURL=followers.js.map //# sourceMappingURL=followers.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{680: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),p=o(6),i=o(1),u=o(56),d=o.n(u),l=(o(3),o(21)),b=o(25),h=o(5),f=o.n(h),j=o(26),m=o.n(j),I=o(272),O=o(27),y=o(7),w=o(895),g=o(626),v=o(917),M=o(629),k=o(893),A=o(897),_=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(e){function a(){for(var a,t=arguments.length,o=new Array(t),c=0;c<t;c++)o[c]=arguments[c];return a=e.call.apply(e,[this].concat(o))||this,Object(i.a)(Object(r.a)(a),"handleLoadMore",d()(function(){a.props.dispatch(Object(O.z)(a.props.params.accountId))},300,{leading:!0})),a}Object(p.a)(a,e);var t=a.prototype;return t.componentWillMount=function(){this.props.dispatch(Object(O.A)(this.props.params.accountId)),this.props.dispatch(Object(O.D)(this.props.params.accountId))},t.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)))},t.render=function(){var a=this.props,t=a.shouldUpdateScroll,o=a.accountIds,c=a.hasMore,e=a.blockedBy;if(!a.isAccount)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 n=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,{}),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:n},void 0,e?[]:o.map(function(a){return Object(s.a)(w.a,{id:a,withNote:!1},a)})))},a}(b.a),Object(i.a)(e,"propTypes",{params:f.a.object.isRequired,dispatch:f.a.func.isRequired,shouldUpdateScroll:f.a.func,accountIds:m.a.list,hasMore:f.a.bool,blockedBy:f.a.bool,isAccount:f.a.bool}),c=n))||c}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[26],{727: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(63),d=o.n(u),l=(o(3),o(12)),b=o(19),h=o(5),m=o.n(h),f=o(18),j=o.n(f),I=o(294),O=o(26),y=o(6),w=o(966),g=o(663),v=o(998),M=o(666),k=o(964),A=o(970),_=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}}]);
//# sourceMappingURL=following.js.map //# sourceMappingURL=following.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{683:function(n,a,t){"use strict";t.r(a);var c=t(0),e=(t(3),t(626)),o=t(897);a.default=function(){return Object(c.a)(e.a,{},void 0,Object(c.a)(o.a,{}))}}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[27],{730:function(n,a,t){"use strict";t.r(a);var c=t(0),e=(t(3),t(663)),o=t(970);a.default=function(){return Object(c.a)(e.a,{},void 0,Object(c.a)(o.a,{}))}}}]);
//# sourceMappingURL=generic_not_found.js.map //# sourceMappingURL=generic_not_found.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["webpack:///app/javascript/builds/pleroma/mastofe/app/javascript/mastodon/features/generic_not_found/index.js"],"names":["GenericNotFound","Object","_babel_runtime_helpers_esm_jsx__WEBPACK_IMPORTED_MODULE_0__","_ui_components_column__WEBPACK_IMPORTED_MODULE_2__","_components_missing_indicator__WEBPACK_IMPORTED_MODULE_3__"],"mappings":"sIAUeA,UANS,kBACtBC,OAAAC,EAAA,EAAAD,CAACE,EAAA,EAAD,UACEF,OAAAC,EAAA,EAAAD,CAACG,EAAA,EAAD","file":"features/generic_not_found.js","sourcesContent":["import React from 'react';\nimport Column from '../ui/components/column';\nimport MissingIndicator from '../../components/missing_indicator';\n\nconst GenericNotFound = () => (\n <Column>\n <MissingIndicator />\n </Column>\n);\n\nexport default GenericNotFound;\n"],"sourceRoot":""} {"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/mastodon/features/generic_not_found/index.js"],"names":["GenericNotFound"],"mappings":"sIAUeA,UANS,kBACtB,YAAC,IAAD,UACE,YAAC,IAAD","file":"features/generic_not_found.js","sourcesContent":["import React from 'react';\nimport Column from '../ui/components/column';\nimport MissingIndicator from '../../components/missing_indicator';\n\nconst GenericNotFound = () => (\n <Column>\n <MissingIndicator />\n </Column>\n);\n\nexport default GenericNotFound;\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{700:function(t,e,n){"use strict";n.r(e);var i,a,c,o,s,r,d,u,l,p=n(0),f=n(6),b=n(1),v=(n(3),n(5)),j=n.n(v),O=n(26),m=n.n(O),_=n(21),R=n(25),g=n(7),I=n(31),h=n(61),N=n(48),q=Object(g.f)({remove:{id:"lists.account.remove",defaultMessage:"Remove from list"},add:{id:"lists.account.add",defaultMessage:"Add to list"}}),y=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(f.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(q.remove),onClick:a}):Object(p.a)(N.a,{icon:"plus",title:i.formatMessage(q.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)("i",{className:"fa fa-fw fa-list-ul column-link__icon"}),n.get("title")),Object(p.a)("div",{className:"account__relationship"},void 0,t)))},e}(R.a),Object(b.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(b.a)(a,"defaultProps",{added:!1}),i=c))||i)||i,w=n(191),A=n(97),k=n(98),M=Object(_.connect)(function(){var i=Object(w.d)();return function(t,e){var n=e.accountId;return{account:i(t,n)}}})(o=Object(g.g)((r=s=function(t){function e(){return t.apply(this,arguments)||this}return Object(f.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)(A.a,{account:t,size:36})),Object(p.a)(k.a,{account:t}))))},e}(R.a),Object(b.a)(s,"propTypes",{account:m.a.map.isRequired}),o=r))||o)||o,z=n(980);n.d(e,"default",function(){return J});var C=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}),J=Object(_.connect)(function(t){return{listIds:C(t).map(function(t){return t.get("id")})}},function(e){return{onInitialize:function(t){return e(Object(I.N)(t))},onReset:function(){return e(Object(I.L)())}}})(d=Object(g.g)((l=u=function(t){function e(){return t.apply(this,arguments)||this}Object(f.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)(M,{accountId:e})),Object(p.a)(z.a,{}),Object(p.a)("div",{className:"list-adder__lists"},void 0,n.map(function(t){return Object(p.a)(y,{listId:t},t)})))},e}(R.a),Object(b.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([[30],{753: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(18),m=n.n(O),_=n(12),R=n(19),g=n(6),I=n(29),h=n(53),N=n(40),q=n(25),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(148),k=n(92),M=n(94),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(1072);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}}]);
//# sourceMappingURL=list_adder.js.map //# sourceMappingURL=list_adder.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{716:function(a,e,c){"use strict";c.r(e);var r=c(0),d=(c(3),c(678)),i=c(1096);e.default=function(){return Object(r.a)("div",{className:"column search-page"},void 0,Object(r.a)(d.a,{}),Object(r.a)("div",{className:"drawer__pager"},void 0,Object(r.a)("div",{className:"drawer__inner darker"},void 0,Object(r.a)(i.a,{}))))}}}]);
//# sourceMappingURL=search.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///app/javascript/tank/sources/git/git.pleroma.social/pleroma/mastofe/app/javascript/flavours/glitch/features/search/index.js"],"names":["Search","className"],"mappings":"uIAgBeA,UAZA,kBACb,mBAAKC,UAAU,2BAAf,EACE,YAAC,IAAD,IAEA,mBAAKA,UAAU,sBAAf,EACE,mBAAKA,UAAU,6BAAf,EACE,YAAC,IAAD","file":"features/glitch/async/search.js","sourcesContent":["import React from 'react';\nimport SearchContainer from 'flavours/glitch/features/compose/containers/search_container';\nimport SearchResultsContainer from 'flavours/glitch/features/compose/containers/search_results_container';\n\nconst Search = () => (\n <div className='column search-page'>\n <SearchContainer />\n\n <div className='drawer__pager'>\n <div className='drawer__inner darker'>\n <SearchResultsContainer />\n </div>\n </div>\n </div>\n);\n\nexport default Search;\n"],"sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{702:function(e,t,n){"use strict";n.r(t);var o,i,c=n(0),a=n(2),s=n(6),l=n(1),r=n(3),u=n.n(r),h=n(21),d=n(35),p=n(904),m=n(633),b=n(628),f=n(222),g=n(7),O=n(933),j=Object(g.g)(o=function(e){function t(){return e.apply(this,arguments)||this}return Object(s.a)(t,e),t.prototype.render=function(){var e=this.props,t=e.settings,n=e.onChange;return Object(c.a)("div",{},void 0,Object(c.a)("span",{className:"column-settings__section"},void 0,Object(c.a)(g.b,{id:"home.column_settings.basic",defaultMessage:"Basic"})),Object(c.a)("div",{className:"column-settings__row"},void 0,Object(c.a)(O.a,{prefix:"home_timeline",settings:t,settingPath:["shows","reblog"],onChange:n,label:Object(c.a)(g.b,{id:"home.column_settings.show_reblogs",defaultMessage:"Show boosts"})})),Object(c.a)("div",{className:"column-settings__row"},void 0,Object(c.a)(O.a,{prefix:"home_timeline",settings:t,settingPath:["shows","reply"],onChange:n,label:Object(c.a)(g.b,{id:"home.column_settings.show_replies",defaultMessage:"Show replies"})})))},t}(u.a.PureComponent))||o,v=n(70),_=Object(h.connect)(function(e){return{settings:e.getIn(["settings","home"])}},function(n){return{onChange:function(e,t){n(Object(v.c)(["home"].concat(e),t))},onSave:function(){n(Object(v.d)())}}})(j),M=n(358);n.d(t,"default",function(){return P});var w=Object(g.f)({title:{id:"column.home",defaultMessage:"Home"}}),P=Object(h.connect)(function(e){return{hasUnread:0<e.getIn(["timelines","home","unread"]),isPartial:e.getIn(["timelines","home","isPartial"])}})(i=Object(g.g)(i=function(i){function e(){for(var o,e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return o=i.call.apply(i,[this].concat(t))||this,Object(l.a)(Object(a.a)(o),"handlePin",function(){var e=o.props,t=e.columnId,n=e.dispatch;n(t?Object(f.h)(t):Object(f.e)("HOME",{}))}),Object(l.a)(Object(a.a)(o),"handleMove",function(e){var t=o.props,n=t.columnId;(0,t.dispatch)(Object(f.g)(n,e))}),Object(l.a)(Object(a.a)(o),"handleHeaderClick",function(){o.column.scrollTop()}),Object(l.a)(Object(a.a)(o),"setRef",function(e){o.column=e}),Object(l.a)(Object(a.a)(o),"handleLoadMore",function(e){o.props.dispatch(Object(d.s)({maxId:e}))}),o}Object(s.a)(e,i);var t=e.prototype;return t.componentDidMount=function(){this._checkIfReloadNeeded(!1,this.props.isPartial)},t.componentDidUpdate=function(e){this._checkIfReloadNeeded(e.isPartial,this.props.isPartial)},t.componentWillUnmount=function(){this._stopPolling()},t._checkIfReloadNeeded=function(e,t){var n=this.props.dispatch;e!==t&&(!e&&t?this.polling=setInterval(function(){n(Object(d.s)())},3e3):e&&!t&&this._stopPolling())},t._stopPolling=function(){this.polling&&(clearInterval(this.polling),this.polling=null)},t.render=function(){var e=this.props,t=e.intl,n=e.shouldUpdateScroll,o=e.hasUnread,i=e.columnId,a=e.multiColumn,s=!!i;return u.a.createElement(m.a,{ref:this.setRef,label:t.formatMessage(w.title)},Object(c.a)(b.a,{icon:"home",active:o,title:t.formatMessage(w.title),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:s,multiColumn:a},void 0,Object(c.a)(_,{})),Object(c.a)(p.a,{trackScroll:!s,scrollKey:"home_timeline-"+i,onLoadMore:this.handleLoadMore,timelineId:"home",emptyMessage:Object(c.a)(g.b,{id:"empty_column.home",defaultMessage:"Your home timeline is empty! Visit {public} or use search to get started and meet other users.",values:{public:Object(c.a)(M.a,{to:"/timelines/public"},void 0,Object(c.a)(g.b,{id:"empty_column.home.public_timeline",defaultMessage:"the public timeline"}))}}),shouldUpdateScroll:n}))},e}(u.a.PureComponent))||i)||i}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[33],{755:function(e,t,n){"use strict";n.r(t);var o,i,a=n(0),c=n(2),s=n(7),l=n(1),r=n(3),u=n.n(r),h=n(12),d=n(35),m=n(977),p=n(669),b=n(665),f=n(245),g=n(6),O=n(1023),j=Object(g.g)(o=function(e){function t(){return e.apply(this,arguments)||this}return Object(s.a)(t,e),t.prototype.render=function(){var e=this.props,t=e.settings,n=e.onChange;return Object(a.a)("div",{},void 0,Object(a.a)("span",{className:"column-settings__section"},void 0,Object(a.a)(g.b,{id:"home.column_settings.basic",defaultMessage:"Basic"})),Object(a.a)("div",{className:"column-settings__row"},void 0,Object(a.a)(O.a,{prefix:"home_timeline",settings:t,settingPath:["shows","reblog"],onChange:n,label:Object(a.a)(g.b,{id:"home.column_settings.show_reblogs",defaultMessage:"Show boosts"})})),Object(a.a)("div",{className:"column-settings__row"},void 0,Object(a.a)(O.a,{prefix:"home_timeline",settings:t,settingPath:["shows","reply"],onChange:n,label:Object(a.a)(g.b,{id:"home.column_settings.show_replies",defaultMessage:"Show replies"})})))},t}(u.a.PureComponent))||o,v=n(72),_=Object(h.connect)(function(e){return{settings:e.getIn(["settings","home"])}},function(e){return{onChange:function(t,n){e(Object(v.c)(["home"].concat(t),n))},onSave:function(){e(Object(v.d)())}}})(j),M=n(310);n.d(t,"default",function(){return P});var w=Object(g.f)({title:{id:"column.home",defaultMessage:"Home"}}),P=Object(h.connect)(function(e){return{hasUnread:e.getIn(["timelines","home","unread"])>0,isPartial:e.getIn(["timelines","home","isPartial"])}})(i=Object(g.g)(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(l.a)(Object(c.a)(t),"handlePin",function(){var e=t.props,n=e.columnId,o=e.dispatch;o(n?Object(f.h)(n):Object(f.e)("HOME",{}))}),Object(l.a)(Object(c.a)(t),"handleMove",function(e){var n=t.props,o=n.columnId;(0,n.dispatch)(Object(f.g)(o,e))}),Object(l.a)(Object(c.a)(t),"handleHeaderClick",function(){t.column.scrollTop()}),Object(l.a)(Object(c.a)(t),"setRef",function(e){t.column=e}),Object(l.a)(Object(c.a)(t),"handleLoadMore",function(e){t.props.dispatch(Object(d.t)({maxId:e}))}),t}Object(s.a)(t,e);var n=t.prototype;return n.componentDidMount=function(){this._checkIfReloadNeeded(!1,this.props.isPartial)},n.componentDidUpdate=function(e){this._checkIfReloadNeeded(e.isPartial,this.props.isPartial)},n.componentWillUnmount=function(){this._stopPolling()},n._checkIfReloadNeeded=function(e,t){var n=this.props.dispatch;e!==t&&(!e&&t?this.polling=setInterval(function(){n(Object(d.t)())},3e3):e&&!t&&this._stopPolling())},n._stopPolling=function(){this.polling&&(clearInterval(this.polling),this.polling=null)},n.render=function(){var e=this.props,t=e.intl,n=e.shouldUpdateScroll,o=e.hasUnread,i=e.columnId,c=e.multiColumn,s=!!i;return u.a.createElement(p.a,{bindToDocument:!c,ref:this.setRef,label:t.formatMessage(w.title)},Object(a.a)(b.a,{icon:"home",active:o,title:t.formatMessage(w.title),onPin:this.handlePin,onMove:this.handleMove,onClick:this.handleHeaderClick,pinned:s,multiColumn:c},void 0,Object(a.a)(_,{})),Object(a.a)(m.a,{trackScroll:!s,scrollKey:"home_timeline-"+i,onLoadMore:this.handleLoadMore,timelineId:"home",emptyMessage:Object(a.a)(g.b,{id:"empty_column.home",defaultMessage:"Your home timeline is empty! Visit {public} or use search to get started and meet other users.",values:{public:Object(a.a)(M.a,{to:"/timelines/public"},void 0,Object(a.a)(g.b,{id:"empty_column.home.public_timeline",defaultMessage:"the public timeline"}))}}),shouldUpdateScroll:n,bindToDocument:!c}))},t}(u.a.PureComponent))||i)||i}}]);
//# sourceMappingURL=home_timeline.js.map //# sourceMappingURL=home_timeline.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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