From 9fad2c52c072c0651a6a6d8ac41dac07c30946dc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:18:58 +0900 Subject: [PATCH 01/38] Bump derailed_benchmarks from 1.3.6 to 1.4.0 (#12007) Bumps [derailed_benchmarks](https://github.com/schneems/derailed_benchmarks) from 1.3.6 to 1.4.0. - [Release notes](https://github.com/schneems/derailed_benchmarks/releases) - [Changelog](https://github.com/schneems/derailed_benchmarks/blob/master/CHANGELOG.md) - [Commits](https://github.com/schneems/derailed_benchmarks/compare/v1.3.6...v1.4.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0478c6e61b..64191c1a02 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -188,13 +188,14 @@ GEM css_parser (1.7.0) addressable debug_inspector (0.0.3) - derailed_benchmarks (1.3.6) + derailed_benchmarks (1.4.0) benchmark-ips (~> 2) get_process_mem (~> 0) heapy (~> 0) memory_profiler (~> 0) rack (>= 1) rake (> 10, < 13) + ruby-statistics (>= 2.1) thor (~> 0.19) devise (4.7.1) bcrypt (~> 3.0) @@ -265,7 +266,8 @@ GEM fuubar (2.4.1) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) - get_process_mem (0.2.3) + get_process_mem (0.2.4) + ffi (~> 1.0) globalid (0.4.2) activesupport (>= 4.2.0) goldfinger (2.1.0) @@ -568,6 +570,7 @@ GEM ruby-progressbar (1.10.1) ruby-saml (1.9.0) nokogiri (>= 1.5.10) + ruby-statistics (2.1.1) rufus-scheduler (3.5.2) fugit (~> 1.1, >= 1.1.5) safe_yaml (1.0.5) From 3fe7d78eb296db17f53551bbaf336bd0daddbccb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:19:18 +0900 Subject: [PATCH 02/38] Bump webmock from 3.7.5 to 3.7.6 (#12008) Bumps [webmock](https://github.com/bblimke/webmock) from 3.7.5 to 3.7.6. - [Release notes](https://github.com/bblimke/webmock/releases) - [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md) - [Commits](https://github.com/bblimke/webmock/compare/v3.7.5...v3.7.6) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 64191c1a02..a84cbd6c5a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -655,7 +655,7 @@ GEM uniform_notifier (1.12.1) warden (1.2.8) rack (>= 2.0.6) - webmock (3.7.5) + webmock (3.7.6) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) From e320f240f6e11a6c9d04d119a6f2444898ef1ffe Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:19:54 +0900 Subject: [PATCH 03/38] Bump tty-command from 0.8.2 to 0.9.0 (#12009) Bumps [tty-command](https://github.com/piotrmurach/tty-command) from 0.8.2 to 0.9.0. - [Release notes](https://github.com/piotrmurach/tty-command/releases) - [Changelog](https://github.com/piotrmurach/tty-command/blob/master/CHANGELOG.md) - [Commits](https://github.com/piotrmurach/tty-command/compare/v0.8.2...v0.9.0) Signed-off-by: dependabot-preview[bot] --- Gemfile | 2 +- Gemfile.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index f6ee3b52e5..3019b1ace0 100644 --- a/Gemfile +++ b/Gemfile @@ -89,7 +89,7 @@ gem 'simple_form', '~> 4.1' gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie' gem 'stoplight', '~> 2.1.3' gem 'strong_migrations', '~> 0.4' -gem 'tty-command', '~> 0.8', require: false +gem 'tty-command', '~> 0.9', require: false gem 'tty-prompt', '~> 0.19', require: false gem 'twitter-text', '~> 1.14' gem 'tzinfo-data', '~> 1.2019' diff --git a/Gemfile.lock b/Gemfile.lock index a84cbd6c5a..7b538849f2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -234,7 +234,7 @@ GEM faraday multi_json encryptor (3.0.0) - equatable (0.5.0) + equatable (0.6.1) erubi (1.8.0) et-orbi (1.1.6) tzinfo @@ -429,9 +429,9 @@ GEM parser (2.6.4.0) ast (~> 2.4.0) parslet (1.8.2) - pastel (0.7.2) - equatable (~> 0.5.0) - tty-color (~> 0.4.0) + pastel (0.7.3) + equatable (~> 0.6) + tty-color (~> 0.5) pg (1.1.4) pghero (2.3.0) activerecord (>= 5) @@ -629,8 +629,8 @@ GEM thor (0.20.3) thread_safe (0.3.6) tilt (2.0.9) - tty-color (0.4.3) - tty-command (0.8.2) + tty-color (0.5.0) + tty-command (0.9.0) pastel (~> 0.7.0) tty-cursor (0.7.0) tty-prompt (0.19.0) @@ -794,7 +794,7 @@ DEPENDENCIES streamio-ffmpeg (~> 3.0) strong_migrations (~> 0.4) thor (~> 0.20) - tty-command (~> 0.8) + tty-command (~> 0.9) tty-prompt (~> 0.19) twitter-text (~> 1.14) tzinfo-data (~> 1.2019) From d269b178a353d385979e7c9ece27421870430450 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:21:22 +0900 Subject: [PATCH 04/38] Bump eslint from 6.4.0 to 6.5.0 (#12017) Bumps [eslint](https://github.com/eslint/eslint) from 6.4.0 to 6.5.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v6.4.0...v6.5.0) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 28 +++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 382e0b8d36..48a8680f2f 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "babel-jest": "^24.9.0", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", - "eslint": "^6.4.0", + "eslint": "^6.5.0", "eslint-plugin-import": "~2.18.2", "eslint-plugin-jsx-a11y": "~6.2.3", "eslint-plugin-promise": "~4.2.1", diff --git a/yarn.lock b/yarn.lock index d2b31036fd..e58de1222b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3917,10 +3917,10 @@ eslint@^2.7.0: text-table "~0.2.0" user-home "^2.0.0" -eslint@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a" - integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA== +eslint@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.5.0.tgz#304623eec903969dd5c9f2d61c6ce3d6ecec8750" + integrity sha512-IIbSW+vKOqMatPmS9ayyku4tvWxHY2iricSRtOz6+ZA5IPRlgXzEL0u/j6dr4eha0ugmhMwDTqxtmNu3kj9O4w== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -4001,12 +4001,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.0.0, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -9390,21 +9385,16 @@ selfsigned@^1.10.6: dependencies: node-forge "0.8.2" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.1, semver@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= -semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" From 115c58e9a2c2c51b78405ac952f5b88aff4d5051 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:21:56 +0900 Subject: [PATCH 05/38] Bump faker from 2.4.0 to 2.5.0 (#12010) Bumps [faker](https://github.com/faker-ruby/faker) from 2.4.0 to 2.5.0. - [Release notes](https://github.com/faker-ruby/faker/releases) - [Changelog](https://github.com/faker-ruby/faker/blob/master/CHANGELOG.md) - [Commits](https://github.com/faker-ruby/faker/compare/v2.4.0...v2.5.0) Signed-off-by: dependabot-preview[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 3019b1ace0..6f1fcb6f10 100644 --- a/Gemfile +++ b/Gemfile @@ -116,7 +116,7 @@ end group :test do gem 'capybara', '~> 3.29' gem 'climate_control', '~> 0.2' - gem 'faker', '~> 2.4' + gem 'faker', '~> 2.5' gem 'microformats', '~> 4.1' gem 'rails-controller-testing', '~> 1.0' gem 'rspec-sidekiq', '~> 3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 7b538849f2..2e7e855cf0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -240,7 +240,7 @@ GEM tzinfo excon (0.62.0) fabrication (2.20.2) - faker (2.4.0) + faker (2.5.0) i18n (~> 1.6.0) faraday (0.15.4) multipart-post (>= 1.2, < 3) @@ -709,7 +709,7 @@ DEPENDENCIES doorkeeper (~> 5.2) dotenv-rails (~> 2.7) fabrication (~> 2.20) - faker (~> 2.4) + faker (~> 2.5) fast_blank (~> 1.0) fastimage fog-core (<= 2.1.0) From a20b492b7516644a67660f9a9dc71cd27fd23ec5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:23:32 +0900 Subject: [PATCH 06/38] Bump tesseract.js from 2.0.0-alpha.15 to 2.0.0-alpha.16 (#12013) Bumps [tesseract.js](https://github.com/naptha/tesseract.js) from 2.0.0-alpha.15 to 2.0.0-alpha.16. - [Release notes](https://github.com/naptha/tesseract.js/releases) - [Commits](https://github.com/naptha/tesseract.js/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- yarn.lock | 24 +++++++++--------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 48a8680f2f..433496b84a 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "stringz": "^2.0.0", "substring-trie": "^1.0.2", "terser-webpack-plugin": "^1.4.1", - "tesseract.js": "^2.0.0-alpha.15", + "tesseract.js": "^2.0.0-alpha.16", "throng": "^4.0.0", "tiny-queue": "^0.2.1", "uuid": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index e58de1222b..74323bf5bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6996,11 +6996,6 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" -node-fetch@^2.3.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - node-forge@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.2.tgz#b4bcc59fb12ce77a8825fc6a783dfe3182499c5a" @@ -10085,10 +10080,10 @@ terser@^4.1.2: source-map "~0.6.1" source-map-support "~0.5.12" -tesseract.js-core@^2.0.0-beta.11: - version "2.0.0-beta.11" - resolved "https://registry.yarnpkg.com/tesseract.js-core/-/tesseract.js-core-2.0.0-beta.11.tgz#c35e3e689efad30138603977ad7eaaac44c7fd37" - integrity sha512-07haKH2JYYo0OfIJoioMS9dDiI5Hrl7+r1MqjeNAAT5WpKO0ATe4cpncC8s1kz0e3s1kaC5WOwL3YJcjbJE+hg== +tesseract.js-core@^2.0.0-beta.12: + version "2.0.0-beta.13" + resolved "https://registry.yarnpkg.com/tesseract.js-core/-/tesseract.js-core-2.0.0-beta.13.tgz#a21d798e88098898a9bdd935d0553215e03274f8" + integrity sha512-GboWV/aV5h+Whito6L6Q3WCFZ2+lgxZGgjY84wSpWbTLEkkZgHsU+dz1or+3rWSABH/nuzHDco1bZRk5+f94mw== tesseract.js-utils@^1.0.0-beta.8: version "1.0.0-beta.8" @@ -10102,18 +10097,17 @@ tesseract.js-utils@^1.0.0-beta.8: is-url "^1.2.4" zlibjs "^0.3.1" -tesseract.js@^2.0.0-alpha.15: - version "2.0.0-alpha.15" - resolved "https://registry.yarnpkg.com/tesseract.js/-/tesseract.js-2.0.0-alpha.15.tgz#9887f4d1c10e25bb098fde7a10580c865c362fad" - integrity sha512-qM1XUFVlTO+tx6oVRpd9QQ8PwQLxo3qhbfIHByUlUVIqWx6y/U9xlHIaG033/Tjfs2EQ0NAehPTOJ+eNElsXEg== +tesseract.js@^2.0.0-alpha.16: + version "2.0.0-alpha.16" + resolved "https://registry.yarnpkg.com/tesseract.js/-/tesseract.js-2.0.0-alpha.16.tgz#1e17717234a1464481abe12283f2c3ac79603d2e" + integrity sha512-8g3je2Kl8rkAFtpmwilGGj+8rCiPClNQaCjW6IafOPNn7hzFnVdL6fU6rG1Xsrc4Twv0HOa75kbpx5u70/WbTA== dependencies: axios "^0.18.0" check-types "^7.4.0" is-url "1.2.2" - node-fetch "^2.3.0" opencollective-postinstall "^2.0.2" resolve-url "^0.2.1" - tesseract.js-core "^2.0.0-beta.11" + tesseract.js-core "^2.0.0-beta.12" tesseract.js-utils "^1.0.0-beta.8" test-exclude@^5.0.0: From b5db577715ba305348c1bdb1555e978336864ae7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 10:23:55 +0900 Subject: [PATCH 07/38] Bump pkg-config from 1.3.8 to 1.3.9 (#12011) Bumps [pkg-config](https://github.com/ruby-gnome/pkg-config) from 1.3.8 to 1.3.9. - [Release notes](https://github.com/ruby-gnome/pkg-config/releases) - [Changelog](https://github.com/ruby-gnome/pkg-config/blob/master/NEWS) - [Commits](https://github.com/ruby-gnome/pkg-config/compare/1.3.8...1.3.9) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2e7e855cf0..3d44b7baa3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -435,7 +435,7 @@ GEM pg (1.1.4) pghero (2.3.0) activerecord (>= 5) - pkg-config (1.3.8) + pkg-config (1.3.9) premailer (1.11.1) addressable css_parser (>= 1.6.0) From 4592c69b07973ea80a2aa77becf330fce37b0d4a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2019 11:11:36 +0900 Subject: [PATCH 08/38] Bump capistrano from 3.11.1 to 3.11.2 (#12012) * Bump capistrano from 3.11.1 to 3.11.2 Bumps [capistrano](https://github.com/capistrano/capistrano) from 3.11.1 to 3.11.2. - [Release notes](https://github.com/capistrano/capistrano/releases) - [Commits](https://github.com/capistrano/capistrano/compare/v3.11.1...v3.11.2) Signed-off-by: dependabot-preview[bot] * Bump capistrano from 3.11.1 to 3.11.2 --- Gemfile.lock | 4 ++-- config/deploy.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3d44b7baa3..3c52f378fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,7 +93,7 @@ GEM tzinfo (~> 1.1) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - airbrussh (1.3.3) + airbrussh (1.3.4) sshkit (>= 1.6.1, != 1.7.0) annotate (2.7.5) activerecord (>= 3.2, < 7.0) @@ -142,7 +142,7 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 0.18) byebug (11.0.0) - capistrano (3.11.1) + capistrano (3.11.2) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) diff --git a/config/deploy.rb b/config/deploy.rb index c4133e7946..4dc36c65c2 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -lock '3.11.1' +lock '3.11.2' set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git') set :branch, ENV.fetch('BRANCH', 'master') From c4fbfaf0b85a589fd669d097471be6bfb82620c6 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Sun, 6 Oct 2019 11:30:07 +0900 Subject: [PATCH 09/38] Remove unused option from tootctl accounts cull (#12074) --- lib/mastodon/accounts_cli.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb index a09a6ab040..6dbb756899 100644 --- a/lib/mastodon/accounts_cli.rb +++ b/lib/mastodon/accounts_cli.rb @@ -211,7 +211,6 @@ module Mastodon end option :concurrency, type: :numeric, default: 5, aliases: [:c] - option :verbose, type: :boolean, aliases: [:v] option :dry_run, type: :boolean desc 'cull', 'Remove remote accounts that no longer exist' long_desc <<-LONG_DESC From 086fc7ed7733c7ec3b51a2513d496670f6a97219 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 6 Oct 2019 06:20:57 +0200 Subject: [PATCH 10/38] Fix S3 adapter retrying failing uploads with exponential backoff (#12085) The default limit of 10 retries with exponential backoff meant that if the S3 server was timing out, you would be stuck with it for much, much longer than the 5 second read timeout we expect. The uploading happens within a database transaction, which means a failing S3 server could negatively affect database performance --- config/initializers/paperclip.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index f308c28411..a0253f4bc0 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -40,6 +40,7 @@ if ENV['S3_ENABLED'] == 'true' http_open_timeout: 5, http_read_timeout: 5, http_idle_timeout: 5, + retry_limit: 0, } ) From a7917269d30104d0ba1e310d5f30f72891c9a37b Mon Sep 17 00:00:00 2001 From: Hugo Gameiro Date: Sun, 6 Oct 2019 18:48:26 +0100 Subject: [PATCH 11/38] add loglevel fatal to video and audio styles (#12088) --- app/models/media_attachment.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 630dab55ae..9c6c04556e 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -57,6 +57,7 @@ class MediaAttachment < ApplicationRecord small: { convert_options: { output: { + 'loglevel' => 'fatal', vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease', }, }, @@ -70,6 +71,7 @@ class MediaAttachment < ApplicationRecord keep_same_format: true, convert_options: { output: { + 'loglevel' => 'fatal', 'map_metadata' => '-1', 'c:v' => 'copy', 'c:a' => 'copy', @@ -84,6 +86,7 @@ class MediaAttachment < ApplicationRecord content_type: 'audio/mpeg', convert_options: { output: { + 'loglevel' => 'fatal', 'q:a' => 2, }, }, From efda126914bf409ca07a9446415b508811a58022 Mon Sep 17 00:00:00 2001 From: Mareena Kunjachan Date: Mon, 7 Oct 2019 01:06:26 +0530 Subject: [PATCH 12/38] Fix spelling error in README (#12086) fix a spelling error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d18a4ee22..d50c1b3bc0 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Private posts, locked accounts, phrase filtering, muting, blocking and all sorts **OAuth2 and a straightforward REST API** -Mastodon acts as an OAuth2 provider so 3rd party apps can use the REST and Streaming APIs, resulting in a rich app ecosystem with a lot of choice! +Mastodon acts as an OAuth2 provider so 3rd party apps can use the REST and Streaming APIs, resulting in a rich app ecosystem with a lot of choices! ## Deployment From f665901e3c0930fb8b3741f6bc6f6a15dd0343f6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 6 Oct 2019 22:11:17 +0200 Subject: [PATCH 13/38] Fix performance of home feed regeneration (#12084) Fetching statuses from all followed accounts at once takes too long within Postgres. Fetching them one by one and merging in Ruby could be a lot less resource-intensive Because the query for dynamically fetching the home timeline is so heavy, we can no longer offer it when the home timeline is missing --- .../api/v1/timelines/home_controller.rb | 6 +- app/javascript/mastodon/actions/timelines.js | 2 +- .../mastodon/components/missing_indicator.js | 23 ++-- .../components/regeneration_indicator.js | 18 +++ .../mastodon/components/status_list.js | 15 +-- .../features/generic_not_found/index.js | 2 +- .../styles/mastodon/components.scss | 30 ++--- .../styles/mastodon/introduction.scss | 3 +- app/lib/feed_manager.rb | 106 +++++++++++++----- app/models/home_feed.rb | 16 +-- app/models/status.rb | 4 - spec/models/home_feed_spec.rb | 5 +- spec/models/status_spec.rb | 43 ------- 13 files changed, 132 insertions(+), 141 deletions(-) create mode 100644 app/javascript/mastodon/components/regeneration_indicator.js diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index fcd0757f1a..ff5ede1385 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -13,7 +13,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id), - status: regeneration_in_progress? ? 206 : 200 + status: account_home_feed.regenerating? ? 206 : 200 end private @@ -62,8 +62,4 @@ class Api::V1::Timelines::HomeController < Api::BaseController def pagination_since_id @statuses.first.id end - - def regeneration_in_progress? - Redis.current.exists("account:#{current_account.id}:regeneration") - end end diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js index 7eeba2aa7f..bc2ac5e823 100644 --- a/app/javascript/mastodon/actions/timelines.js +++ b/app/javascript/mastodon/actions/timelines.js @@ -97,7 +97,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) { api(getState).get(path, { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); - dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore, isLoadingRecent && preferPendingItems)); + dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.status === 206, isLoadingRecent, isLoadingMore, isLoadingRecent && preferPendingItems)); done(); }).catch(error => { dispatch(expandTimelineFail(timelineId, error, isLoadingMore)); diff --git a/app/javascript/mastodon/components/missing_indicator.js b/app/javascript/mastodon/components/missing_indicator.js index 70d8c3b984..7b0101bab8 100644 --- a/app/javascript/mastodon/components/missing_indicator.js +++ b/app/javascript/mastodon/components/missing_indicator.js @@ -1,17 +1,24 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; +import illustration from 'mastodon/../images/elephant_ui_disappointed.svg'; +import classNames from 'classnames'; -const MissingIndicator = () => ( -
-
-
+const MissingIndicator = ({ fullPage }) => ( +
+
+ +
-
- - -
+
+ +
); +MissingIndicator.propTypes = { + fullPage: PropTypes.bool, +}; + export default MissingIndicator; diff --git a/app/javascript/mastodon/components/regeneration_indicator.js b/app/javascript/mastodon/components/regeneration_indicator.js new file mode 100644 index 0000000000..faf88c6b50 --- /dev/null +++ b/app/javascript/mastodon/components/regeneration_indicator.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import illustration from 'mastodon/../images/elephant_ui_working.svg'; + +const MissingIndicator = () => ( +
+
+ +
+ +
+ + +
+
+); + +export default MissingIndicator; diff --git a/app/javascript/mastodon/components/status_list.js b/app/javascript/mastodon/components/status_list.js index 745e6422d3..e1b370c913 100644 --- a/app/javascript/mastodon/components/status_list.js +++ b/app/javascript/mastodon/components/status_list.js @@ -1,12 +1,12 @@ import { debounce } from 'lodash'; import React from 'react'; -import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import StatusContainer from '../containers/status_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import LoadGap from './load_gap'; import ScrollableList from './scrollable_list'; +import RegenerationIndicator from 'mastodon/components/regeneration_indicator'; export default class StatusList extends ImmutablePureComponent { @@ -81,18 +81,7 @@ export default class StatusList extends ImmutablePureComponent { const { isLoading, isPartial } = other; if (isPartial) { - return ( -
-
-
- -
- - -
-
-
- ); + return ; } let scrollableContent = (isLoading || statusIds.size > 0) ? ( diff --git a/app/javascript/mastodon/features/generic_not_found/index.js b/app/javascript/mastodon/features/generic_not_found/index.js index 0290be47f9..41cd61a5f8 100644 --- a/app/javascript/mastodon/features/generic_not_found/index.js +++ b/app/javascript/mastodon/features/generic_not_found/index.js @@ -4,7 +4,7 @@ import MissingIndicator from '../../components/missing_indicator'; const GenericNotFound = () => ( - + ); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a6675b8edb..d9182ade94 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3127,37 +3127,27 @@ a.status-card.compact:hover { cursor: default; display: flex; flex: 1 1 auto; + flex-direction: column; align-items: center; justify-content: center; padding: 20px; - & > div { - width: 100%; - background: transparent; - padding-top: 0; - } - &__figure { - background: url('../images/elephant_ui_working.svg') no-repeat center 0; - width: 100%; - height: 160px; - background-size: contain; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); + &, + img { + display: block; + width: auto; + height: 160px; + margin: 0; + } } - &.missing-indicator { + &--without-header { padding-top: 20px + 48px; - - .regeneration-indicator__figure { - background-image: url('../images/elephant_ui_disappointed.svg'); - } } &__label { - margin-top: 200px; + margin-top: 30px; strong { display: block; diff --git a/app/javascript/styles/mastodon/introduction.scss b/app/javascript/styles/mastodon/introduction.scss index 222d8f60e8..b44ae73064 100644 --- a/app/javascript/styles/mastodon/introduction.scss +++ b/app/javascript/styles/mastodon/introduction.scss @@ -3,9 +3,10 @@ flex-direction: column; justify-content: center; align-items: center; + height: 100vh; + background: $ui-base-color; @media screen and (max-width: 920px) { - background: darken($ui-base-color, 8%); display: block !important; } diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 871ec5c194..d8b486b609 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -19,7 +19,7 @@ class FeedManager def filter?(timeline_type, status, receiver_id) if timeline_type == :home - filter_from_home?(status, receiver_id) + filter_from_home?(status, receiver_id, build_crutches(receiver_id, [status])) elsif timeline_type == :mentions filter_from_mentions?(status, receiver_id) else @@ -29,6 +29,7 @@ class FeedManager def push_to_home(account, status) return false unless add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?) + trim(:home, account.id) PushUpdateWorker.perform_async(account.id, status.id, "timeline:#{account.id}") if push_update_required?("timeline:#{account.id}") true @@ -36,6 +37,7 @@ class FeedManager def unpush_from_home(account, status) return false unless remove_from_feed(:home, account.id, status, account.user&.aggregates_reblogs?) + redis.publish("timeline:#{account.id}", Oj.dump(event: :delete, payload: status.id.to_s)) true end @@ -46,7 +48,9 @@ class FeedManager should_filter &&= !ListAccount.where(list_id: list.id, account_id: status.in_reply_to_account_id).exists? return false if should_filter end + return false unless add_to_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?) + trim(:list, list.id) PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}") if push_update_required?("timeline:list:#{list.id}") true @@ -54,6 +58,7 @@ class FeedManager def unpush_from_list(list, status) return false unless remove_from_feed(:list, list.id, status, list.account.user&.aggregates_reblogs?) + redis.publish("timeline:list:#{list.id}", Oj.dump(event: :delete, payload: status.id.to_s)) true end @@ -85,16 +90,21 @@ class FeedManager def merge_into_timeline(from_account, into_account) timeline_key = key(:home, into_account.id) - query = from_account.statuses.limit(FeedManager::MAX_ITEMS / 4) + aggregate = into_account.user&.aggregates_reblogs? + query = from_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, reblog: :account).limit(FeedManager::MAX_ITEMS / 4) if redis.zcard(timeline_key) >= FeedManager::MAX_ITEMS / 4 - oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0 + oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i query = query.where('id > ?', oldest_home_score) end - query.each do |status| - next if status.direct_visibility? || status.limited_visibility? || filter?(:home, status, into_account) - add_to_feed(:home, into_account.id, status, into_account.user&.aggregates_reblogs?) + statuses = query.to_a + crutches = build_crutches(into_account.id, statuses) + + statuses.each do |status| + next if filter_from_home?(status, into_account, crutches) + + add_to_feed(:home, into_account.id, status, aggregate) end trim(:home, into_account.id) @@ -120,24 +130,35 @@ class FeedManager end def populate_feed(account) - added = 0 - limit = FeedManager::MAX_ITEMS / 2 - max_id = nil + limit = FeedManager::MAX_ITEMS / 2 + aggregate = account.user&.aggregates_reblogs? + timeline_key = key(:home, account.id) - loop do - statuses = Status.as_home_timeline(account) - .paginate_by_max_id(limit, max_id) + account.statuses.where.not(visibility: :direct).limit(limit).each do |status| + add_to_feed(:home, account.id, status, aggregate) + end - break if statuses.empty? + account.following.includes(:account_stat).find_each do |target_account| + if redis.zcard(timeline_key) >= limit + oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i + last_status_score = Mastodon::Snowflake.id_at(account.last_status_at) - statuses.each do |status| - next if filter_from_home?(status, account) - added += 1 if add_to_feed(:home, account.id, status, account.user&.aggregates_reblogs?) + # If the feed is full and this account has not posted more recently + # than the last item on the feed, then we can skip the whole account + # because none of its statuses would stay on the feed anyway + next if last_status_score < oldest_home_score end - break unless added.zero? + statuses = target_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, reblog: :account).limit(limit) + crutches = build_crutches(account.id, statuses) + + statuses.each do |status| + next if filter_from_home?(status, account, crutches) + + add_to_feed(:home, account.id, status, aggregate) + end - max_id = statuses.last.id + trim(:home, account.id) end end @@ -152,31 +173,33 @@ class FeedManager (context == :home ? Mute.where(account_id: receiver_id, target_account_id: account_ids).any? : Mute.where(account_id: receiver_id, target_account_id: account_ids, hide_notifications: true).any?) end - def filter_from_home?(status, receiver_id) + def filter_from_home?(status, receiver_id, crutches) return false if receiver_id == status.account_id return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) return true if phrase_filtered?(status, receiver_id, :home) - check_for_blocks = status.active_mentions.pluck(:account_id) + check_for_blocks = crutches[:active_mentions][status.id] || [] check_for_blocks.concat([status.account_id]) if status.reblog? check_for_blocks.concat([status.reblog.account_id]) - check_for_blocks.concat(status.reblog.active_mentions.pluck(:account_id)) + check_for_blocks.concat(crutches[:active_mentions][status.reblog_of_id] || []) end - return true if blocks_or_mutes?(receiver_id, check_for_blocks, :home) + return true if check_for_blocks.any? { |target_account_id| crutches[:blocking][target_account_id] || crutches[:muting][target_account_id] } if status.reply? && !status.in_reply_to_account_id.nil? # Filter out if it's a reply - should_filter = !Follow.where(account_id: receiver_id, target_account_id: status.in_reply_to_account_id).exists? # and I'm not following the person it's a reply to + should_filter = !crutches[:following][status.in_reply_to_account_id] # and I'm not following the person it's a reply to should_filter &&= receiver_id != status.in_reply_to_account_id # and it's not a reply to me should_filter &&= status.account_id != status.in_reply_to_account_id # and it's not a self-reply - return should_filter + + return !!should_filter elsif status.reblog? # Filter out a reblog - should_filter = Follow.where(account_id: receiver_id, target_account_id: status.account_id, show_reblogs: false).exists? # if the reblogger's reblogs are suppressed - should_filter ||= Block.where(account_id: status.reblog.account_id, target_account_id: receiver_id).exists? # or if the author of the reblogged status is blocking me - should_filter ||= AccountDomainBlock.where(account_id: receiver_id, domain: status.reblog.account.domain).exists? # or the author's domain is blocked - return should_filter + should_filter = crutches[:hiding_reblogs][status.account_id] # if the reblogger's reblogs are suppressed + should_filter ||= crutches[:blocked_by][status.reblog.account_id] # or if the author of the reblogged status is blocking me + should_filter ||= crutches[:domain_blocking][status.reblog.account.domain] # or the author's domain is blocked + + return !!should_filter end false @@ -308,4 +331,31 @@ class FeedManager redis.zrem(timeline_key, status.id) end + + def build_crutches(receiver_id, statuses) + crutches = {} + + crutches[:active_mentions] = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact).pluck(:status_id, :account_id).each_with_object({}) { |(id, account_id), mapping| (mapping[id] ||= []).push(account_id) } + + check_for_blocks = statuses.flat_map do |s| + arr = crutches[:active_mentions][s.id] || [] + arr.concat([s.account_id]) + + if s.reblog? + arr.concat([s.reblog.account_id]) + arr.concat(crutches[:active_mentions][s.reblog_of_id] || []) + end + + arr + end + + crutches[:following] = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + crutches[:blocking] = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + crutches[:muting] = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.map { |s| s.reblog&.account&.domain }.compact).pluck(:domain).each_with_object({}) { |domain, mapping| mapping[domain] = true } + crutches[:blocked_by] = Block.where(target_account_id: receiver_id, account_id: statuses.map { |s| s.reblog&.account_id }.compact).pluck(:account_id).each_with_object({}) { |id, mapping| mapping[id] = true } + + crutches + end end diff --git a/app/models/home_feed.rb b/app/models/home_feed.rb index ba7564983b..1fd506138b 100644 --- a/app/models/home_feed.rb +++ b/app/models/home_feed.rb @@ -7,19 +7,7 @@ class HomeFeed < Feed @account = account end - def get(limit, max_id = nil, since_id = nil, min_id = nil) - if redis.exists("account:#{@account.id}:regeneration") - from_database(limit, max_id, since_id, min_id) - else - super - end - end - - private - - def from_database(limit, max_id, since_id, min_id) - Status.as_home_timeline(@account) - .paginate_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id) - .reject { |status| FeedManager.instance.filter?(:home, status, @account.id) } + def regenerating? + redis.exists("account:#{@id}:regeneration") end end diff --git a/app/models/status.rb b/app/models/status.rb index 3504ac3709..0c01a5389d 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -282,10 +282,6 @@ class Status < ApplicationRecord where(language: nil).or where(language: account.chosen_languages) end - def as_home_timeline(account) - where(account: [account] + account.following).where(visibility: [:public, :unlisted, :private]) - end - def as_public_timeline(account = nil, local_only = false) query = timeline_scope(local_only).without_replies diff --git a/spec/models/home_feed_spec.rb b/spec/models/home_feed_spec.rb index 3acb997f1f..ee7a83960a 100644 --- a/spec/models/home_feed_spec.rb +++ b/spec/models/home_feed_spec.rb @@ -34,11 +34,10 @@ RSpec.describe HomeFeed, type: :model do Redis.current.set("account:#{account.id}:regeneration", true) end - it 'gets statuses with ids in the range from database' do + it 'returns nothing' do results = subject.get(3) - expect(results.map(&:id)).to eq [10, 3, 2] - expect(results.first.attributes.keys).to include('id', 'updated_at') + expect(results.map(&:id)).to eq [] end end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index a8c5674147..51a10cd177 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -296,49 +296,6 @@ RSpec.describe Status, type: :model do end end - describe '.as_home_timeline' do - let(:account) { Fabricate(:account) } - let(:followed) { Fabricate(:account) } - let(:not_followed) { Fabricate(:account) } - - before do - Fabricate(:follow, account: account, target_account: followed) - - @self_status = Fabricate(:status, account: account, visibility: :public) - @self_direct_status = Fabricate(:status, account: account, visibility: :direct) - @followed_status = Fabricate(:status, account: followed, visibility: :public) - @followed_direct_status = Fabricate(:status, account: followed, visibility: :direct) - @not_followed_status = Fabricate(:status, account: not_followed, visibility: :public) - - @results = Status.as_home_timeline(account) - end - - it 'includes statuses from self' do - expect(@results).to include(@self_status) - end - - it 'does not include direct statuses from self' do - expect(@results).to_not include(@self_direct_status) - end - - it 'includes statuses from followed' do - expect(@results).to include(@followed_status) - end - - it 'does not include direct statuses mentioning recipient from followed' do - Fabricate(:mention, account: account, status: @followed_direct_status) - expect(@results).to_not include(@followed_direct_status) - end - - it 'does not include direct statuses not mentioning recipient from followed' do - expect(@results).not_to include(@followed_direct_status) - end - - it 'does not include statuses from non-followed' do - expect(@results).not_to include(@not_followed_status) - end - end - describe '.as_public_timeline' do it 'only includes statuses with public visibility' do public_status = Fabricate(:status, visibility: :public) From a58218562555c32bd0ec6c2ca2cc19ac4984904c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 6 Oct 2019 22:11:29 +0200 Subject: [PATCH 14/38] Fix `GET /api/v1/instance` REST APIs being unavailable in secure mode (#12089) --- app/controllers/api/v1/instances/activity_controller.rb | 1 + app/controllers/api/v1/instances/peers_controller.rb | 1 + app/controllers/api/v1/instances_controller.rb | 1 + 3 files changed, 3 insertions(+) diff --git a/app/controllers/api/v1/instances/activity_controller.rb b/app/controllers/api/v1/instances/activity_controller.rb index 4fb5a69d8b..b30e8464c3 100644 --- a/app/controllers/api/v1/instances/activity_controller.rb +++ b/app/controllers/api/v1/instances/activity_controller.rb @@ -4,6 +4,7 @@ class Api::V1::Instances::ActivityController < Api::BaseController before_action :require_enabled_api! skip_before_action :set_cache_headers + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? respond_to :json diff --git a/app/controllers/api/v1/instances/peers_controller.rb b/app/controllers/api/v1/instances/peers_controller.rb index 75c3cb4ba8..cc00d8a6bc 100644 --- a/app/controllers/api/v1/instances/peers_controller.rb +++ b/app/controllers/api/v1/instances/peers_controller.rb @@ -4,6 +4,7 @@ class Api::V1::Instances::PeersController < Api::BaseController before_action :require_enabled_api! skip_before_action :set_cache_headers + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? respond_to :json diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb index 8d8231423e..c323b60b42 100644 --- a/app/controllers/api/v1/instances_controller.rb +++ b/app/controllers/api/v1/instances_controller.rb @@ -4,6 +4,7 @@ class Api::V1::InstancesController < Api::BaseController respond_to :json skip_before_action :set_cache_headers + skip_before_action :require_authenticated_user!, unless: :whitelist_mode? def show expires_in 3.minutes, public: true From 8386d9ec1001f8a938224190e518db054751b5a9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 03:56:21 +0200 Subject: [PATCH 15/38] Fix hashtag timeline REST API accepting too many hashtags (#12091) --- app/services/hashtag_query_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/hashtag_query_service.rb b/app/services/hashtag_query_service.rb index 282821710a..196de06392 100644 --- a/app/services/hashtag_query_service.rb +++ b/app/services/hashtag_query_service.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class HashtagQueryService < BaseService + LIMIT_PER_MODE = 4 + def call(tag, params, account = nil, local = false) tags = tags_for(Array(tag.name) | Array(params[:any])).pluck(:id) all = tags_for(params[:all]) @@ -15,6 +17,6 @@ class HashtagQueryService < BaseService private def tags_for(names) - Tag.matching_name(names) if names.presence + Tag.matching_name(Array(names).take(LIMIT_PER_MODE)) if names.present? end end From b5be067c88151f75e09fc7d8b558ad4ccd51867b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 04:14:36 +0200 Subject: [PATCH 16/38] Fix existing user records with now-renamed `pt` locale (#12092) Fix #12082 --- .../20191007013357_update_pt_locales.rb | 11 ++++++++ db/schema.rb | 26 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20191007013357_update_pt_locales.rb diff --git a/db/migrate/20191007013357_update_pt_locales.rb b/db/migrate/20191007013357_update_pt_locales.rb new file mode 100644 index 0000000000..b7288d38a0 --- /dev/null +++ b/db/migrate/20191007013357_update_pt_locales.rb @@ -0,0 +1,11 @@ +class UpdatePtLocales < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def up + User.where(locale: 'pt').in_batches.update_all(locale: 'pt-PT') + end + + def down + User.where(locale: 'pt-PT').in_batches.update_all(locale: 'pt') + end +end diff --git a/db/schema.rb b/db/schema.rb index 2d516965c5..62e2d3a6d6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_10_01_213028) do +ActiveRecord::Schema.define(version: 2019_10_07_013357) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -693,6 +693,30 @@ ActiveRecord::Schema.define(version: 2019_10_01_213028) do t.index ["tag_id", "status_id"], name: "index_statuses_tags_on_tag_id_and_status_id", unique: true end + create_table "stream_entries", force: :cascade do |t| + t.bigint "activity_id" + t.string "activity_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "hidden", default: false, null: false + t.bigint "account_id" + t.index ["account_id", "activity_type", "id"], name: "index_stream_entries_on_account_id_and_activity_type_and_id" + t.index ["activity_id", "activity_type"], name: "index_stream_entries_on_activity_id_and_activity_type" + end + + create_table "subscriptions", force: :cascade do |t| + t.string "callback_url", default: "", null: false + t.string "secret" + t.datetime "expires_at" + t.boolean "confirmed", default: false, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.datetime "last_successful_delivery_at" + t.string "domain" + t.bigint "account_id", null: false + t.index ["account_id", "callback_url"], name: "index_subscriptions_on_account_id_and_callback_url", unique: true + end + create_table "tags", force: :cascade do |t| t.string "name", default: "", null: false t.datetime "created_at", null: false From 38b6c34e32e2624b1c110809428642dcd1f69c82 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 04:24:05 +0200 Subject: [PATCH 17/38] Fix issues with tootctl's parallelization and progress reporting (#12093) --- lib/mastodon/cli_helper.rb | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/mastodon/cli_helper.rb b/lib/mastodon/cli_helper.rb index da73483493..c2950dffa3 100644 --- a/lib/mastodon/cli_helper.rb +++ b/lib/mastodon/cli_helper.rb @@ -15,6 +15,11 @@ module Mastodon end def parallelize_with_progress(scope) + if options[:concurrency] < 1 + say('Cannot run with this concurrency setting, must be at least 1', :red) + exit(1) + end + ActiveRecord::Base.configurations[Rails.env]['pool'] = options[:concurrency] progress = create_progress_bar(scope.count) @@ -27,17 +32,26 @@ module Mastodon items.each do |item| futures << Concurrent::Future.execute(executor: pool) do - ActiveRecord::Base.connection_pool.with_connection do - begin - progress.log("Processing #{item.id}") if options[:verbose] - - result = yield(item) - aggregate.increment(result) if result.is_a?(Integer) - rescue => e - progress.log pastel.red("Error processing #{item.id}: #{e}") - ensure - progress.increment + begin + if !progress.total.nil? && progress.progress + 1 > progress.total + # The number of items has changed between start and now, + # since there is no good way to predict the final count from + # here, just change the progress bar to an indeterminate one + + progress.total = nil end + + progress.log("Processing #{item.id}") if options[:verbose] + + result = ActiveRecord::Base.connection_pool.with_connection do + yield(item) + end + + aggregate.increment(result) if result.is_a?(Integer) + rescue => e + progress.log pastel.red("Error processing #{item.id}: #{e}") + ensure + progress.increment end end end @@ -46,7 +60,7 @@ module Mastodon futures.map(&:value) end - progress.finish + progress.stop [total.value, aggregate.value] end From 95f21ab87f3d459311c411cf429ac051a668218f Mon Sep 17 00:00:00 2001 From: trwnh Date: Sun, 6 Oct 2019 21:33:31 -0500 Subject: [PATCH 18/38] Add missing back button header for invalid account (#12094) Should fix #6786 --- app/javascript/mastodon/features/account_timeline/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js index 69bab1e86e..8d0cbe5a19 100644 --- a/app/javascript/mastodon/features/account_timeline/index.js +++ b/app/javascript/mastodon/features/account_timeline/index.js @@ -83,6 +83,7 @@ class AccountTimeline extends ImmutablePureComponent { if (!isAccount) { return ( + ); From 0336621c8026dcbe0d9d19358673cc175a18e613 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 04:36:32 +0200 Subject: [PATCH 19/38] Update AUTHORS.md (#12096) --- AUTHORS.md | 666 ++++++++++++++++++++--------------------------------- 1 file changed, 244 insertions(+), 422 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 8d3aaf480d..5f5985fba8 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -5,89 +5,100 @@ Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon) and provided thanks to the work of the following contributors: * [Gargron](https://github.com/Gargron) -* [ykzts](https://github.com/ykzts) * [ThibG](https://github.com/ThibG) +* [ykzts](https://github.com/ykzts) +* [dependabot[bot]](https://github.com/apps/dependabot) * [akihikodaki](https://github.com/akihikodaki) +* [dependabot-preview[bot]](https://github.com/apps/dependabot-preview) * [mjankowski](https://github.com/mjankowski) -* [dependabot[bot]](https://github.com/apps/dependabot) * [unarist](https://github.com/unarist) -* [m4sk1n](https://github.com/m4sk1n) * [yiskah](https://github.com/yiskah) * [nolanlawson](https://github.com/nolanlawson) * [ysksn](https://github.com/ysksn) -* [sorin-davidoi](https://github.com/sorin-davidoi) * [abcang](https://github.com/abcang) +* [sorin-davidoi](https://github.com/sorin-davidoi) * [lynlynlynx](https://github.com/lynlynlynx) * [mayaeh](https://github.com/mayaeh) +* [m4sk1n](mailto:me@m4sk.in) +* [Marcin Mikołajczak](mailto:me@m4sk.in) +* [Kjwon15](https://github.com/Kjwon15) * [renatolond](https://github.com/renatolond) * [alpaca-tc](https://github.com/alpaca-tc) +* [jeroenpraat](https://github.com/jeroenpraat) * [nclm](https://github.com/nclm) * [ineffyble](https://github.com/ineffyble) -* [jeroenpraat](https://github.com/jeroenpraat) +* [mabkenar](https://github.com/mabkenar) * [blackle](https://github.com/blackle) * [Quent-in](https://github.com/Quent-in) * [JantsoP](https://github.com/JantsoP) -* [Kjwon15](https://github.com/Kjwon15) -* [mabkenar](https://github.com/mabkenar) +* [zunda](https://github.com/zunda) * [nullkal](https://github.com/nullkal) * [yookoala](https://github.com/yookoala) +* [Aditoo17](https://github.com/Aditoo17) +* [Quenty31](https://github.com/Quenty31) +* [marek-lach](https://github.com/marek-lach) * [shuheiktgw](https://github.com/shuheiktgw) * [ashfurrow](https://github.com/ashfurrow) -* [zunda](https://github.com/zunda) -* [Quenty31](https://github.com/Quenty31) * [eramdam](https://github.com/eramdam) +* [noellabo](https://github.com/noellabo) * [takayamaki](https://github.com/takayamaki) +* [danhunsaker](https://github.com/danhunsaker) * [masarakki](https://github.com/masarakki) * [ticky](https://github.com/ticky) -* [danhunsaker](https://github.com/danhunsaker) * [ThisIsMissEm](https://github.com/ThisIsMissEm) * [hcmiya](https://github.com/hcmiya) * [stephenburgess8](https://github.com/stephenburgess8) * [Wonderfall](https://github.com/Wonderfall) * [matteoaquila](https://github.com/matteoaquila) * [yukimochi](https://github.com/yukimochi) +* [palindromordnilap](https://github.com/palindromordnilap) * [rkarabut](https://github.com/rkarabut) * [Artoria2e5](https://github.com/Artoria2e5) * [nightpool](https://github.com/nightpool) * [marrus-sh](https://github.com/marrus-sh) +* [hinaloe](https://github.com/hinaloe) * [krainboltgreene](https://github.com/krainboltgreene) * [pfigel](https://github.com/pfigel) * [Aldarone](https://github.com/Aldarone) * [BoFFire](https://github.com/BoFFire) * [clworld](https://github.com/clworld) +* [MasterGroosha](https://github.com/MasterGroosha) * [dracos](https://github.com/dracos) +* [MaciekBaron](https://github.com/MaciekBaron) * [SerCom_KC](mailto:sercom-kc@users.noreply.github.com) * [Sylvhem](https://github.com/Sylvhem) -* [MasterGroosha](https://github.com/MasterGroosha) +* [MitarashiDango](https://github.com/MitarashiDango) * [JeanGauthier](https://github.com/JeanGauthier) * [kschaper](https://github.com/kschaper) -* [MaciekBaron](https://github.com/MaciekBaron) -* [MitarashiDango](mailto:mitarashidango@users.noreply.github.com) * [beatrix-bitrot](https://github.com/beatrix-bitrot) -* [Aditoo17](https://github.com/Aditoo17) +* [angristan](https://github.com/angristan) * [adbelle](https://github.com/adbelle) * [evanminto](https://github.com/evanminto) * [MightyPork](https://github.com/MightyPork) +* [ashleyhull-versent](mailto:ashley.hull@versent.com.au) * [yhirano55](https://github.com/yhirano55) * [rinsuki](https://github.com/rinsuki) * [camponez](https://github.com/camponez) -* [hinaloe](https://github.com/hinaloe) -* [SerCom-KC](https://github.com/SerCom-KC) +* [SerCom_KC](mailto:szescxz@gmail.com) * [aschmitz](https://github.com/aschmitz) +* [trwnh](https://github.com/trwnh) * [devkral](https://github.com/devkral) * [fpiesche](https://github.com/fpiesche) +* [hugogameiro](https://github.com/hugogameiro) * [gandaro](https://github.com/gandaro) * [johnsudaar](https://github.com/johnsudaar) +* [ariasuni](https://github.com/ariasuni) * [trebmuh](https://github.com/trebmuh) -* [Rakib Hasan](mailto:rmhasan@gmail.com) -* [ashleyhull-versent](https://github.com/ashleyhull-versent) +* [rmhasan](https://github.com/rmhasan) +* [kedamaDQ](https://github.com/kedamaDQ) * [lindwurm](https://github.com/lindwurm) * [victorhck](mailto:victorhck@geeko.site) * [voidsatisfaction](https://github.com/voidsatisfaction) +* [BenLubar](https://github.com/BenLubar) * [hikari-no-yume](https://github.com/hikari-no-yume) -* [angristan](https://github.com/angristan) * [seefood](https://github.com/seefood) * [jackjennings](https://github.com/jackjennings) +* [koyuawsmbrtn](https://github.com/koyuawsmbrtn) * [spla](mailto:spla@mastodont.cat) * [expenses](https://github.com/expenses) * [walf443](https://github.com/walf443) @@ -95,18 +106,17 @@ and provided thanks to the work of the following contributors: * [mistydemeo](https://github.com/mistydemeo) * [dunn](https://github.com/dunn) * [xqus](https://github.com/xqus) -* [hugogameiro](https://github.com/hugogameiro) -* [ariasuni](https://github.com/ariasuni) * [pfm-eyesightjp](https://github.com/pfm-eyesightjp) * [fakenine](https://github.com/fakenine) +* [Shleeble](https://github.com/Shleeble) * [tsuwatch](https://github.com/tsuwatch) * [victorhck](https://github.com/victorhck) -* [kedamaDQ](https://github.com/kedamaDQ) +* [mkljczk](https://github.com/mkljczk) +* [manuelviens](https://github.com/manuelviens) * [puckipedia](https://github.com/puckipedia) -* [trwnh](https://github.com/trwnh) * [fvh-P](https://github.com/fvh-P) +* [rtucker](https://github.com/rtucker) * [Anna e só](mailto:contraexemplos@gmail.com) -* [BenLubar](https://github.com/BenLubar) * [kazu9su](https://github.com/kazu9su) * [Komic](https://github.com/Komic) * [lmorchard](https://github.com/lmorchard) @@ -119,6 +129,7 @@ and provided thanks to the work of the following contributors: * [goofy-bz](mailto:goofy@babelzilla.org) * [kadiix](https://github.com/kadiix) * [kodacs](https://github.com/kodacs) +* [marcin mikołajczak](mailto:me@m4sk.in) * [JMendyk](https://github.com/JMendyk) * [KScl](https://github.com/KScl) * [sterdev](https://github.com/sterdev) @@ -129,30 +140,31 @@ and provided thanks to the work of the following contributors: * [northerner](https://github.com/northerner) * [fhemberger](https://github.com/fhemberger) * [greysteil](https://github.com/greysteil) -* [hensmith](https://github.com/hensmith) +* [hencatsmith](https://github.com/hencatsmith) * [d6rkaiz](https://github.com/d6rkaiz) * [Reverite](https://github.com/Reverite) * [JohnD28](https://github.com/JohnD28) * [znz](https://github.com/znz) -* [marek-lach](https://github.com/marek-lach) * [Naouak](https://github.com/Naouak) * [pawelngei](https://github.com/pawelngei) -* [rtucker](https://github.com/rtucker) * [reneklacan](https://github.com/reneklacan) * [ekiru](https://github.com/ekiru) -* [noellabo](https://github.com/noellabo) * [tcitworld](https://github.com/tcitworld) * [geta6](https://github.com/geta6) * [happycoloredbanana](https://github.com/happycoloredbanana) * [leopku](https://github.com/leopku) * [SansPseudoFix](https://github.com/SansPseudoFix) +* [salvadorpla](https://github.com/salvadorpla) * [tomfhowe](https://github.com/tomfhowe) * [noraworld](https://github.com/noraworld) * [theboss](https://github.com/theboss) +* [nzws](https://github.com/nzws) * [178inaba](https://github.com/178inaba) +* [xgess](https://github.com/xgess) * [alyssais](https://github.com/alyssais) -* [hiphref](https://github.com/hiphref) +* [aablinov](https://github.com/aablinov) * [stalker314314](https://github.com/stalker314314) +* [cutls](https://github.com/cutls) * [huertanix](https://github.com/huertanix) * [genesixx](https://github.com/genesixx) * [halkeye](https://github.com/halkeye) @@ -162,21 +174,24 @@ and provided thanks to the work of the following contributors: * [kmichl](https://github.com/kmichl) * [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name) * [saper](https://github.com/saper) +* [Dar13](https://github.com/Dar13) * [nevillepark](https://github.com/nevillepark) * [ornithocoder](https://github.com/ornithocoder) +* [pwoolcoc](https://github.com/pwoolcoc) * [pierreozoux](https://github.com/pierreozoux) * [qguv](https://github.com/qguv) * [Ram Lmn](mailto:ramlmn@users.noreply.github.com) -* [sascha-sl](https://github.com/sascha-sl) +* [aurelia-sl](https://github.com/aurelia-sl) * [harukasan](https://github.com/harukasan) * [stamak](https://github.com/stamak) -* [Technowix](mailto:technowix@users.noreply.github.com) +* [Technowix](https://github.com/Technowix) * [Zoeille](https://github.com/Zoeille) * [Thor Harald Johansen](mailto:thj@thj.no) * [0x70b1a5](https://github.com/0x70b1a5) * [gled-rs](https://github.com/gled-rs) * [Valentin_NC](mailto:valentin.ouvrard@nautile.sarl) * [R0ckweb](https://github.com/R0ckweb) +* [unasuke](https://github.com/unasuke) * [caasi](https://github.com/caasi) * [chr-1x](https://github.com/chr-1x) * [esetomo](https://github.com/esetomo) @@ -184,8 +199,9 @@ and provided thanks to the work of the following contributors: * [hoodie](mailto:hoodiekitten@outlook.com) * [luzi82](https://github.com/luzi82) * [duxovni](https://github.com/duxovni) +* [slice](https://github.com/slice) * [tmm576](https://github.com/tmm576) -* [unsmell](https://github.com/unsmell) +* [unsmell](mailto:unsmell@users.noreply.github.com) * [valerauko](https://github.com/valerauko) * [chriswmartin](https://github.com/chriswmartin) * [vahnj](https://github.com/vahnj) @@ -193,21 +209,25 @@ and provided thanks to the work of the following contributors: * [AndreLewin](https://github.com/AndreLewin) * [0xflotus](https://github.com/0xflotus) * [redtachyons](https://github.com/redtachyons) +* [acid-chicken](https://github.com/acid-chicken) * [thurloat](https://github.com/thurloat) * [aaribaud](https://github.com/aaribaud) * [pointlessone](https://github.com/pointlessone) * [Andrew](mailto:andrewlchronister@gmail.com) +* [aurelien-reeves](https://github.com/aurelien-reeves) +* [AnaGelez](https://github.com/AnaGelez) * [estuans](https://github.com/estuans) * [dissolve](https://github.com/dissolve) * [PurpleBooth](https://github.com/PurpleBooth) * [bradurani](https://github.com/bradurani) * [wavebeem](https://github.com/wavebeem) * [bruwalfas](https://github.com/bruwalfas) -* [foxsan48](https://github.com/foxsan48) +* [LottieVixen](https://github.com/LottieVixen) * [wchristian](https://github.com/wchristian) * [muffinista](https://github.com/muffinista) * [cdutson](https://github.com/cdutson) * [farlistener](https://github.com/farlistener) +* [dariusk](https://github.com/dariusk) * [DavidLibeau](https://github.com/DavidLibeau) * [ddevault](https://github.com/ddevault) * [Fjoerfoks](https://github.com/Fjoerfoks) @@ -216,6 +236,7 @@ and provided thanks to the work of the following contributors: * [Gomasy](https://github.com/Gomasy) * [unstabler](https://github.com/unstabler) * [potato4d](https://github.com/potato4d) +* [Hanage999](https://github.com/Hanage999) * [h-izumi](https://github.com/h-izumi) * [ErikXXon](https://github.com/ErikXXon) * [ian-kelling](https://github.com/ian-kelling) @@ -231,21 +252,23 @@ and provided thanks to the work of the following contributors: * [Kaylee](mailto:kaylee@codethat.sucks) * [Kazhnuz](https://github.com/Kazhnuz) * [connyduck](https://github.com/connyduck) -* [Lindsey Bieda](mailto:lindseyb@users.noreply.github.com) +* [LindseyB](https://github.com/LindseyB) * [Lorenz Diener](mailto:halcyon@icosahedron.website) * [alimony](https://github.com/alimony) * [mig5](https://github.com/mig5) * [moritzheiber](https://github.com/moritzheiber) * [ndarville](https://github.com/ndarville) * [Abzol](https://github.com/Abzol) -* [pwoolcoc](https://github.com/pwoolcoc) +* [PatOnTheBack](https://github.com/PatOnTheBack) * [xPaw](https://github.com/xPaw) * [petzah](https://github.com/petzah) * [ignisf](https://github.com/ignisf) * [raymestalez](https://github.com/raymestalez) * [remram44](https://github.com/remram44) * [sts10](https://github.com/sts10) +* [SuperSandro2000](https://github.com/SuperSandro2000) * [u1-liquid](https://github.com/u1-liquid) +* [rosylilly](https://github.com/rosylilly) * [sim6](https://github.com/sim6) * [Sir-Boops](https://github.com/Sir-Boops) * [stemid](https://github.com/stemid) @@ -270,6 +293,7 @@ and provided thanks to the work of the following contributors: * [cpsdqs](https://github.com/cpsdqs) * [barzamin](https://github.com/barzamin) * [fhalna](https://github.com/fhalna) +* [highemerly](https://github.com/highemerly) * [haoyayoi](https://github.com/haoyayoi) * [ik11235](https://github.com/ik11235) * [kawax](https://github.com/kawax) @@ -279,6 +303,7 @@ and provided thanks to the work of the following contributors: * [mecab](https://github.com/mecab) * [nicobz25](https://github.com/nicobz25) * [oliverkeeble](https://github.com/oliverkeeble) +* [partev](https://github.com/partev) * [pinfort](https://github.com/pinfort) * [rbaumert](https://github.com/rbaumert) * [rhoio](https://github.com/rhoio) @@ -287,19 +312,17 @@ and provided thanks to the work of the following contributors: * [vjackson725](https://github.com/vjackson725) * [wxcafe](https://github.com/wxcafe) * [新都心(Neet Shin)](mailto:nucx@dio-vox.com) +* [clarfon](https://github.com/clarfon) * [cygnan](https://github.com/cygnan) * [Awea](https://github.com/Awea) * [halcy](https://github.com/halcy) -* [naaaaaaaaaaaf](https://github.com/naaaaaaaaaaaf) * [8398a7](https://github.com/8398a7) * [857b](https://github.com/857b) * [insom](https://github.com/insom) * [tachyons](https://github.com/tachyons) -* [acid-chicken](https://github.com/acid-chicken) * [Esteth](https://github.com/Esteth) * [unascribed](https://github.com/unascribed) * [Aguay-val](https://github.com/Aguay-val) -* [Akihiko Odaki](mailto:nekomanma@pixiv.co.jp) * [knu](https://github.com/knu) * [h3poteto](https://github.com/h3poteto) * [unleashed](https://github.com/unleashed) @@ -307,8 +330,8 @@ and provided thanks to the work of the following contributors: * [console-cowboy](https://github.com/console-cowboy) * [Alkarex](https://github.com/Alkarex) * [a2](https://github.com/a2) +* [alfiedotwtf](https://github.com/alfiedotwtf) * [0xa](https://github.com/0xa) -* [palindromordnilap](https://github.com/palindromordnilap) * [virtualpain](https://github.com/virtualpain) * [sapphirus](https://github.com/sapphirus) * [amandavisconti](https://github.com/amandavisconti) @@ -320,10 +343,9 @@ and provided thanks to the work of the following contributors: * [contraexemplo](https://github.com/contraexemplo) * [abackstrom](https://github.com/abackstrom) * [armandfardeau](https://github.com/armandfardeau) +* [raboof](https://github.com/raboof) * [jumbosushi](https://github.com/jumbosushi) -* [aurelien-reeves](https://github.com/aurelien-reeves) * [ayumin](https://github.com/ayumin) -* [BaptisteGelez](https://github.com/BaptisteGelez) * [bzg](https://github.com/bzg) * [benediktg](https://github.com/benediktg) * [blakebarnett](https://github.com/blakebarnett) @@ -337,15 +359,15 @@ and provided thanks to the work of the following contributors: * [DoubleMalt](https://github.com/DoubleMalt) * [Moosh-be](https://github.com/Moosh-be) * [Motoma](https://github.com/Motoma) -* [chriswk](https://github.com/chriswk) +* [Christopher Kolstad](mailto:christopher.kolstad@finn.no) * [csu](https://github.com/csu) -* [clarfon](https://github.com/clarfon) * [kklleemm](https://github.com/kklleemm) * [colindean](https://github.com/colindean) * [dachinat](https://github.com/dachinat) * [multiple-creatures](https://github.com/multiple-creatures) * [watilde](https://github.com/watilde) * [daprice](https://github.com/daprice) +* [da2x](https://github.com/da2x) * [dar5hak](https://github.com/dar5hak) * [kant](https://github.com/kant) * [maxolasersquad](https://github.com/maxolasersquad) @@ -354,7 +376,7 @@ and provided thanks to the work of the following contributors: * [davefp](https://github.com/davefp) * [yipdw](https://github.com/yipdw) * [debanshuk](https://github.com/debanshuk) -* [Derek Lewis](mailto:derekcecillewis@gmail.com) +* [DerekNonGeneric](https://github.com/DerekNonGeneric) * [dblandin](https://github.com/dblandin) * [Drew Gates](mailto:aranaur@users.noreply.github.com) * [dtschust](https://github.com/dtschust) @@ -366,11 +388,13 @@ and provided thanks to the work of the following contributors: * [ericblade](https://github.com/ericblade) * [mikoim](https://github.com/mikoim) * [espenronnevik](https://github.com/espenronnevik) +* [fabianonline](https://github.com/fabianonline) * [Finariel](https://github.com/Finariel) * [siuying](https://github.com/siuying) * [zoc](https://github.com/zoc) * [fwenzel](https://github.com/fwenzel) * [GenbuHase](https://github.com/GenbuHase) +* [nilsding](https://github.com/nilsding) * [hattori6789](https://github.com/hattori6789) * [algernon](https://github.com/algernon) * [Fastbyte01](https://github.com/Fastbyte01) @@ -386,17 +410,19 @@ and provided thanks to the work of the following contributors: * [suzukaze](https://github.com/suzukaze) * [Hiromi-Kai](https://github.com/Hiromi-Kai) * [hishamhm](https://github.com/hishamhm) +* [Slaynash](https://github.com/Slaynash) * [musashino205](https://github.com/musashino205) * [iwaim](https://github.com/iwaim) * [valrus](https://github.com/valrus) * [IMcD23](https://github.com/IMcD23) * [yi0713](https://github.com/yi0713) * [iblech](https://github.com/iblech) -* [usbsnowcrash](https://github.com/usbsnowcrash) +* [J Yeary](mailto:usbsnowcrash@users.noreply.github.com) * [jack-michaud](https://github.com/jack-michaud) * [Floppy](https://github.com/Floppy) * [loomchild](https://github.com/loomchild) * [jenkr55](https://github.com/jenkr55) +* [hyenagirl64](https://github.com/hyenagirl64) * [press5](https://github.com/press5) * [TrollDecker](https://github.com/TrollDecker) * [jmontane](https://github.com/jmontane) @@ -406,17 +432,17 @@ and provided thanks to the work of the following contributors: * [joshuap](https://github.com/joshuap) * [Tiwy57](https://github.com/Tiwy57) * [xuv](https://github.com/xuv) -* [June Sallou](mailto:jnsll@users.noreply.github.com) +* [Jnsll](https://github.com/Jnsll) * [j0k3r](https://github.com/j0k3r) * [KEINOS](https://github.com/KEINOS) * [futoase](https://github.com/futoase) -* [Pneumaticat](https://github.com/Pneumaticat) +* [pot8to](https://github.com/pot8to) * [Kit Redgrave](mailto:qwertyitis@gmail.com) * [Knut Erik](mailto:abjectio@users.noreply.github.com) * [mkody](https://github.com/mkody) * [k0ta0uchi](https://github.com/k0ta0uchi) * [KrzysiekJ](https://github.com/KrzysiekJ) -* [leowzukw](https://github.com/leowzukw) +* [Leo Wzukw](mailto:leowzukw@users.noreply.github.com) * [Tak](https://github.com/Tak) * [cacheflow](https://github.com/cacheflow) * [ldidry](https://github.com/ldidry) @@ -424,6 +450,7 @@ and provided thanks to the work of the following contributors: * [lfuelling](https://github.com/lfuelling) * [Grabacr07](https://github.com/Grabacr07) * [mistermantas](https://github.com/mistermantas) +* [MareenaKunjachan](https://github.com/MareenaKunjachan) * [mareklach](https://github.com/mareklach) * [wirehack7](https://github.com/wirehack7) * [martymcguire](https://github.com/martymcguire) @@ -431,50 +458,53 @@ and provided thanks to the work of the following contributors: * [otsune](https://github.com/otsune) * [mbugowski](https://github.com/mbugowski) * [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com) +* [madmath03](https://github.com/madmath03) * [matt-auckland](https://github.com/matt-auckland) * [webroo](https://github.com/webroo) -* [matthiasbeyer](https://github.com/matthiasbeyer) -* [mattjmattj](https://github.com/mattjmattj) -* [mtparet](https://github.com/mtparet) -* [maximeborges](https://github.com/maximeborges) -* [minacle](https://github.com/minacle) -* [michaeljdeeb](https://github.com/michaeljdeeb) -* [Themimitoof](https://github.com/Themimitoof) -* [cyweo](https://github.com/cyweo) +* [Matthias Beyer](mailto:mail@beyermatthias.de) +* [Matthias Jouan](mailto:matthias.jouan@gmail.com) +* [Matthieu Paret](mailto:matthieuparet69@gmail.com) +* [Maxime BORGES](mailto:maxime.borges@gmail.com) +* [Mayu Laierlence](mailto:minacle@live.com) +* [Michael Deeb](mailto:michaeldeeb@me.com) +* [Michael Vieira](mailto:dtox94@gmail.com) +* [Michel](mailto:michel@cyweo.com) * [Midgard](mailto:m1dgard@users.noreply.github.com) -* [mike-burns](https://github.com/mike-burns) -* [verymilan](https://github.com/verymilan) -* [milmazz](https://github.com/milmazz) -* [premist](https://github.com/premist) -* [Mnkai](https://github.com/Mnkai) -* [mitchhentges](https://github.com/mitchhentges) -* [mouse-reeve](https://github.com/mouse-reeve) -* [Mozinet-fr](https://github.com/Mozinet-fr) -* [lae](https://github.com/lae) -* [nosada](https://github.com/nosada) -* [Nanamachi](https://github.com/Nanamachi) -* [orinthe](https://github.com/orinthe) -* [NecroTechno](https://github.com/NecroTechno) -* [Dar13](https://github.com/Dar13) -* [ngerakines](https://github.com/ngerakines) -* [vonneudeck](https://github.com/vonneudeck) -* [Ninetailed](https://github.com/Ninetailed) -* [k24](https://github.com/k24) -* [noiob](https://github.com/noiob) -* [kwaio](https://github.com/kwaio) -* [norayr](https://github.com/norayr) -* [joyeusenoelle](https://github.com/joyeusenoelle) -* [OlivierNicole](https://github.com/OlivierNicole) -* [noppa](https://github.com/noppa) -* [Otakan951](https://github.com/Otakan951) -* [fahy](https://github.com/fahy) +* [Mike Burns](mailto:mburns@thoughtbot.com) +* [Milan](mailto:me@petabyteboy.de) +* [Milan*](mailto:tchncs@vivaldi.net) +* [Milton Mazzarri](mailto:milmazz@gmail.com) +* [Minku Lee](mailto:premist@me.com) +* [Minori Hiraoka](mailto:mnkai@users.noreply.github.com) +* [Mitchell Hentges](mailto:mitch9654@gmail.com) +* [Mostafa Ahangarha](mailto:ahangarha@users.noreply.github.com) +* [Mouse Reeve](mailto:mousereeve@riseup.net) +* [Mozinet](mailto:mozinet-fr@users.noreply.github.com) +* [Musee U](mailto:lae@users.noreply.github.com) +* [NOGISAKA Sadata](mailto:ngsksdt@gmail.com) +* [Naf](mailto:uenok.htc@gmail.com) +* [Nanamachi](mailto:town7.haruki@gmail.com) +* [Nathaniel Ekoniak](mailto:nekoniak@ennate.tech) +* [NecroTechno](mailto:necrotechno@riseup.net) +* [Nick Gerakines](mailto:nick@gerakines.net) +* [Nicolai von Neudeck](mailto:nicolai@vonneudeck.com) +* [Ninetailed](mailto:ninetailed@gmail.com) +* [Nishi, Keisuke](mailto:k24@users.noreply.github.com) +* [Noiob](mailto:noiob@users.noreply.github.com) +* [Nope Nope](mailto:hireme@kwaio.ninja) +* [Norayr Chilingarian](mailto:norayr@arnet.am) +* [Noëlle Anthony](mailto:noelle.d.anthony@gmail.com) +* [N氏](mailto:uenok.htc@gmail.com) +* [Olivier Nicole](mailto:olivierthnicole@gmail.com) +* [Oskari Noppa](mailto:noppa@users.noreply.github.com) +* [Otakan](mailto:otakan951@gmail.com) +* [Padraig Fahy](mailto:tech@padraigfahy.com) * [PatrickRWells](mailto:32802366+patrickrwells@users.noreply.github.com) * [Paul](mailto:naydex.mc+github@gmail.com) * [Pete Keen](mailto:pete@petekeen.net) * [Pierre-Morgan Gate](mailto:pgate@users.noreply.github.com) * [Ratmir Karabut](mailto:rkarabut@sfmodern.ru) * [Reto Kromer](mailto:retokromer@users.noreply.github.com) -* [Rey Tucker](mailto:git@reytucker.us) * [Rob Watson](mailto:rfwatson@users.noreply.github.com) * [Ryan Freebern](mailto:ryan@freebern.org) * [Ryan Wade](mailto:ryan.wade@protonmail.com) @@ -482,6 +512,7 @@ and provided thanks to the work of the following contributors: * [S.H](mailto:gamelinks007@gmail.com) * [Sadiq Saif](mailto:staticsafe@users.noreply.github.com) * [Sam Hewitt](mailto:hewittsamuel@gmail.com) +* [Sasha Sorokin](mailto:dafri.nochiterov8@gmail.com) * [Satoshi KOJIMA](mailto:skoji@mac.com) * [ScienJus](mailto:i@scienjus.com) * [Scott Larkin](mailto:scott@codeclimate.com) @@ -492,12 +523,10 @@ and provided thanks to the work of the following contributors: * [Shaun Gillies](mailto:me@shaungillies.net) * [Shin Adachi](mailto:shn@glucose.jp) * [Shin Kojima](mailto:shin@kojima.org) -* [Sho Kusano](mailto:rosylilly@aduca.org) * [Shouko Yu](mailto:imshouko@gmail.com) * [Sina Mashek](mailto:sina@mashek.xyz) * [Soshi Kato](mailto:mail@sossii.com) * [Spanky](mailto:2788886+spankyworks@users.noreply.github.com) -* [Stanislas](mailto:angristan@pm.me) * [StefOfficiel](mailto:pichard.stephane@free.fr) * [Steven Tappert](mailto:admin@dark-it.net) * [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com) @@ -506,6 +535,7 @@ and provided thanks to the work of the following contributors: * [Takayoshi Nishida](mailto:takayoshi.nishida@gmail.com) * [Takayuki KUSANO](mailto:github@tkusano.jp) * [TakesxiSximada](mailto:takesxi.sximada@gmail.com) +* [Tao Bror Bojlén](mailto:brortao@users.noreply.github.com) * [TheInventrix](mailto:theinventrix@users.noreply.github.com) * [Thomas Alberola](mailto:thomas@needacoffee.fr) * [Toby Deshane](mailto:fortyseven@users.noreply.github.com) @@ -515,10 +545,12 @@ and provided thanks to the work of the following contributors: * [Treyssat-Vincent Nino](mailto:treyssatvincent@users.noreply.github.com) * [Udo Kramer](mailto:optik@fluffel.io) * [Una](mailto:una@unascribed.com) +* [Ushitora Anqou](mailto:ushitora@anqou.net) * [Ushitora Anqou](mailto:ushitora_anqou@yahoo.co.jp) * [Valentin Lorentz](mailto:progval+git@progval.net) * [Vladimir Mincev](mailto:vladimir@canicinteractive.com) * [Waldir Pimenta](mailto:waldyrious@gmail.com) +* [Wenceslao Páez Chávez](mailto:wcpaez@gmail.com) * [Wesley Ellis](mailto:tahnok@gmail.com) * [Wiktor](mailto:wiktor@metacode.biz) * [Wonderfall](mailto:wonderfall@schrodinger.io) @@ -529,6 +561,7 @@ and provided thanks to the work of the following contributors: * [YaQ](mailto:i_k_o_m_a_7@yahoo.co.jp) * [Yanaken](mailto:yanakend@gmail.com) * [Yann Klis](mailto:yann.klis@gmail.com) +* [Yağızhan](mailto:35808275+yagizhan49@users.noreply.github.com) * [Yeechan Lu](mailto:wz.bluesnow@gmail.com) * [Yusuke Abe](mailto:moonset20@gmail.com) * [Zachary Spector](mailto:logicaldash@gmail.com) @@ -542,6 +575,7 @@ and provided thanks to the work of the following contributors: * [chrolis](mailto:chrolis@users.noreply.github.com) * [cormo](mailto:cormorant2+github@gmail.com) * [d0p1](mailto:dopi-sama@hush.com) +* [dxwc](mailto:dxwc@users.noreply.github.com) * [evilny0](mailto:evilny0@moomoocamp.net) * [febrezo](mailto:felixbrezo@gmail.com) * [fsubal](mailto:fsubal@users.noreply.github.com) @@ -550,6 +584,7 @@ and provided thanks to the work of the following contributors: * [gol-cha](mailto:info@mevo.xyz) * [hakoai](mailto:hk--76@qa2.so-net.ne.jp) * [haosbvnker](mailto:github@chaosbunker.com) +* [ichi_i](mailto:51489410+ichi-i@users.noreply.github.com) * [isati](mailto:phil@juchnowi.cz) * [jacob](mailto:jacobherringtondeveloper@gmail.com) * [jenn kaplan](mailto:me@jkap.io) @@ -561,7 +596,6 @@ and provided thanks to the work of the following contributors: * [karlyeurl](mailto:karl.yeurl@gmail.com) * [kedama](mailto:32974885+kedamadq@users.noreply.github.com) * [kodai](mailto:shirafuta.kodai@gmail.com) -* [koyu](mailto:me@koyu.space) * [kuro5hin](mailto:rusty@kuro5hin.org) * [luzpaz](mailto:luzpaz@users.noreply.github.com) * [maxypy](mailto:maxime@mpigou.fr) @@ -573,6 +607,7 @@ and provided thanks to the work of the following contributors: * [muan](mailto:muan@github.com) * [namelessGonbai](mailto:43787036+namelessgonbai@users.noreply.github.com) * [neetshin](mailto:neetshin@neetsh.in) +* [nzws](mailto:git-yuzu@svk.jp) * [rch850](mailto:rich850@gmail.com) * [roikale](mailto:roikale@users.noreply.github.com) * [rysiekpl](mailto:rysiek@hackerspace.pl) @@ -585,6 +620,8 @@ and provided thanks to the work of the following contributors: * [tateisu](mailto:tateisu@gmail.com) * [tmyt](mailto:shigure@refy.net) * [trevDev()](mailto:trev@trevdev.ca) +* [tsia](mailto:github@tsia.de) +* [umonaca](mailto:53662960+umonaca@users.noreply.github.com) * [utam0k](mailto:k0ma@utam0k.jp) * [vpzomtrrfrt](mailto:vpzomtrrfrt@gmail.com) * [walfie](mailto:walfington@gmail.com) @@ -593,9 +630,10 @@ and provided thanks to the work of the following contributors: * [yoshipc](mailto:yoooo@yoshipc.net) * [Özcan Zafer AYAN](mailto:ozcanzaferayan@gmail.com) * [ばん](mailto:detteiu0321@gmail.com) -* [みたらしだんご](mailto:mitarashidango@users.noreply.github.com) +* [ふるふる](mailto:frfs@users.noreply.github.com) * [りんすき](mailto:6533808+rinsuki@users.noreply.github.com) * [ヨイツの賢狼ホロ | 3rd style](mailto:horo@yoitsu.moe) +* [唐宗勛](mailto:tangzongxun@hotmail.com) * [猫吸血鬼ディフリス / 猫ロキP](mailto:deflis@gmail.com) * [艮 鮟鱇](mailto:ushitora_anqou@yahoo.co.jp) * [西小倉宏信](mailto:nishiko@mindia.jp) @@ -607,338 +645,122 @@ This document is provided for informational purposes only. Since it is only upda Following people have contributed to translation of Mastodon: -- **Albanian** - - Besnik Bleta - - Aditoo -- **Arabic** - - ButterflyOfFire - - Aditoo - - Amrz0 -- **Asturian** - - ButterflyOfFire - - Enol P. - - Aditoo -- **Basque** - - Osoitz - - Aditoo - - Aitzol - - ButterflyOfFire - - Peru Iparragirre - - Gorka Azkarate -- **Bengali** - - dxwc -- **Bulgarian** - - ButterflyOfFire - - Aditoo -- **Catalan** - - spla - - Aditoo - - ButterflyOfFire - - Joan Montané - - Jose Luis -- **Chinese (Hong Kong)** - - ButterflyOfFire - - Luzi Leung - - Aditoo -- **Chinese (Simplified)** - - Allen Zhong - - ButterflyOfFire - - SerCom_KC - - martialarts - - Kaitian Xie - - Aditoo - - pan93412 -- **Chinese (Traditional)** - - Aditoo - - ButterflyOfFire - - James58899 - - pan93412 - - S1ttidoe477 - - SHA265 - - Jeff Huang -- **Corsican** - - Alix D. R. - - Aditoo - - ButterflyOfFire -- **Croatian** - - ButterflyOfFire - - Aditoo -- **Czech** - - Aditoo - - Marek Ľach - - ButterflyOfFire -- **Danish** - - Einhjeriar - - Rasmus Sæderup - - Aditoo - - ButterflyOfFire -- **Dutch** - - Albakham - - ButterflyOfFire - - jeroenpraat - - rscmbbng - - Aditoo - - Jelv -- **English** - - ButterflyOfFire - - Renato "Lond" Cerqueira -- **English (United Kingdom)** - - Albakham -- **Esperanto** - - Aditoo - - ButterflyOfFire - - Becci Cat - - Jeong Arm - - Mélanie Chauvel - - Vanege - - Martin Bodin - - tuxayo/Victor Grousset -- **Finnish** - - ButterflyOfFire - - Mikko Poussu - - Taru Luojola - - S Heija - - Aditoo - - Jonne Arjoranta -- **French** - - Albakham - - Alix D. R. - - ButterflyOfFire - - codl - - Leia - - Alda Marteau-Hardi - - Mélanie Chauvel - - Paul Marques Mota - - azenet - - Olivier Humbert - - Aditoo - - Jonathan Chan - - Letiteuf55 - - Baptiste Jonglez - - goofy-mdn - - Jean-Baptiste Holcroft - - Technowix - - Martin Bodin - - Théodore - - Thibaut Girka - - Franck Paul - - Sylvhem -- **Galician** - - ButterflyOfFire - - Xose M. - - Aditoo - - manequim -- **Georgian** - - ButterflyOfFire - - Aditoo -- **German** - - Aditoo - - ButterflyOfFire - - Daniel - - averageunicorn - - Koyu Berteon - - larsreineke - - koyu - - Austin Jones - - lilo - - Benedikt Geißler - - ePirat - - Eugen Rochko - - Weblate Admin - - Patrick Figel -- **Greek** - - Dimitris Maroulidis - - Antonis - - Aditoo - - ButterflyOfFire - - Konstantinos Grevenitis -- **Hebrew** - - ButterflyOfFire - - Aditoo - - Ira - - Yaron Shahrabani -- **Hungarian** - - ButterflyOfFire - - Adam Paszternak - - Aditoo - - Tibike Miklós -- **Ido** - - ButterflyOfFire - - Aditoo -- **Indonesian** - - afachri - - ButterflyOfFire - - Dito Kurnia Pratama - - Eirworks - - Aditoo - - Alfiana Sibuea - - se7entime -- **Irish** - - Albakham - - Kevin Houlihan -- **Italian** - - Alessandro Levati - - Albakham - - ButterflyOfFire - - Marcin Mikołajczak - - Aditoo - - Giuseppe Pignataro - - Stefano -- **Japanese** - - Hinaloe - - 小鳥遊まりあ - - mayaeh - - osapon - - 森の子リスのミーコの大冒険 - - Kumasun Morino - - Yamagishi Kazutoshi - - Aditoo - - ButterflyOfFire - - Jeong Arm - - unarist -- **Kazakh** - - arshat - - Aditoo -- **Korean** - - Aditoo - - Jeong Arm - - ButterflyOfFire - - Minori Hiraoka - - Yamagishi Kazutoshi -- **Lithuanian** - - Sarunas Medeikis -- **Malay** - - Muhammad Nur Hidayat (MNH48) - - Aditoo - - ButterflyOfFire -- **Norwegian (old code)** - - ButterflyOfFire - - Espen Rønnevik - - Aditoo - - Tale -- **Occitan** - - Aditoo - - ButterflyOfFire - - Quenti2 - - Quentí - - Maxenç -- **Persian** - - Masoud Abkenar - - Aditoo - - ButterflyOfFire -- **Polish** - - Aditoo - - Albakham - - ButterflyOfFire - - Stasiek Michalski - - Marcin Mikołajczak - - Jakub Mendyk - - Marek Ľach - - krkk -- **Portuguese** - - Albakham - - João Pinheiro - - manequim - - Aditoo - - ButterflyOfFire - - Hugo Gameiro -- **Portuguese (Brazil)** - - Aditoo - - Albakham - - Anna e só - - Renato "Lond" Cerqueira - - André Andrade - - ButterflyOfFire -- **Romanian** - - adrianbblk - - ButterflyOfFire - - Aditoo -- **Russian** - - Albakham - - ButterflyOfFire - - Evgeny Petrov - - Aditoo - - Павел Гастелло - - Andrew Zyabin - - Yaron Shahrabani -- **Serbian** - - Branko Kokanovic - - Burekz Finezt - - Aditoo - - ButterflyOfFire -- **Serbian (latin)** - - ButterflyOfFire - - Aditoo -- **Slovak** - - Aditoo - - ButterflyOfFire - - Ivan Pleva - - Marek Ľach - - Peter -- **Slovenian** - - Kristijan Tkalec - - Aditoo - - ButterflyOfFire -- **Spanish** - - Albakham - - ButterflyOfFire - - Carlos Mondragon - - Antón López - - Max Winkler - - Pablo de la Concepción Sanz - - Sergio Soriano - - Angeles Broullón - - Lothar Wolf - - Aditoo - - David Charte - - Emmanuel -- **Swedish** - - ButterflyOfFire - - Isak Holmström - - Shellkr - - Aditoo - - Elias Mårtenson - - Stefan Midjich - - Tim Stahel - - Jonas Hultén -- **Telugu** - - avndp - - Ranjith Tellakula - - Aditoo - - ButterflyOfFire - - Joseph Nuthalapati -- **Thai** - - ButterflyOfFire - - parnikkapore - - Thai Localization - - Aditoo -- **Turkish** - - Ali Demirtas - - ButterflyOfFire - - Aditoo -- **Ukrainian** - - alexcleac - - ButterflyOfFire - - Aditoo - - Ivan Verchenko -- **Welsh** - - carl morris - - Jaz-Michael King - - Owain Rhys Lewis - - Rhoslyn Prys - - Aditoo - - ButterflyOfFire - - Renato "Lond" Cerqueira - - Albakham - - Kevin Beynon -- **Armenian** - - Aditoo - - ButterflyOfFire -- **Latvian** - - Aditoo - - ButterflyOfFire - - Maigonis -- **Tamil** - - Aditoo - - ButterflyOfFire - - Prasanna Venkadesh +- Zoltán Gera (*Hungarian*) +- Kristijan Tkalec (*Slovenian*) +- Evert Prants (*Estonian*) +- borys_sh (*Ukrainian*) +- ButterflyOfFire (*Arabic; French*) +- Osoitz (*Basque*) +- oɹʇuʞ (*Spanish, Argentina*) +- koyu (*German*) +- Jeroen (*Dutch*) +- Muha Aliss (*Turkish*) +- 唐宗勛 (*Chinese Simplified*) +- Jeong Arm (*Korean; Esperanto; Japanese*) +- Oguz Ersen (*Turkish*) +- spla (*Catalan*) +- Ramdziana F Y (*Indonesian*) +- Aditoo17 (*Czech*) +- Xosé M. (*Galician*) +- Roboron (*Spanish*) +- Alix Rossi (*Corsican; French*) +- Maya Minatsuki (*Japanese*) +- Masoud Abkenar (*Persian*) +- Thai Localization (*Thai*) +- Marek Ľach (*Slovak; Polish*) +- d5Ziif3K (*Ukrainian*) +- lamnatos (*Greek*) +- Emyn Nant Nefydd (*Welsh*) +- Diluns (*Occitan*) +- atarashiako (*Chinese Simplified*) +- 101010 (*Polish*) +- Yi-Jyun Pan (*Chinese Traditional*) +- silkevicious (*Italian*) +- FédiQuébec (*French*) +- Jaz-Michael King (*Welsh*) +- christalleras (*Norwegian Nynorsk*) +- tykayn (*French*) +- Alessandro Levati (*Italian*) +- carolinagiorno (*Portuguese, Brazilian*) +- taoxvx (*Danish*) +- sabri (*Spanish*) +- Sasha Sorokin (*Russian*) +- shioko (*Chinese Simplified*) +- Evgeny Petrov (*Russian*) +- ariasuni (*French; Esperanto*) +- Tiago Epifânio (*Portuguese*) +- dxwc (*Bengali*) +- liffon (*Swedish*) +- Vanege (*Esperanto*) +- Johan Schiff (*Swedish*) +- kat (*Ukrainian; Russian*) +- oti4500 (*Hungarian; Ukrainian*) +- Juan José Salvador Piedra (*Spanish*) +- diazepan (*Spanish*) +- SHeija (*Finnish*) +- Jack R (*Spanish*) +- Saederup92 (*Danish*) +- Stasiek Michalski (*Polish*) +- Dewi (*Breton; French*) +- cybergene (*Japanese*) +- AW Unad (*Indonesian*) +- Andrea Lo Iacono (*Italian*) +- Ray (*Spanish*) +- Unmual (*Spanish*) +- Ryo (*Korean*) +- juanda097 (*Spanish*) +- Anunnakey (*Macedonian*) +- Cutls (*Japanese*) +- erikstl (*Esperanto*) +- ruine (*Japanese*) +- MadeInSteak (*Finnish*) +- Sokratis Alichanidis (*Greek*) +- dragnucs2 (*Arabic*) +- frumble (*German*) +- Rikard Linde (*Swedish*) +- PPNplus (*Thai*) +- arethsu (*Swedish*) +- EPEMA YT (*German*) +- Rhys Harrison (*Esperanto*) +- KEINOS (*Japanese*) +- filippodb (*Italian*) +- JzshAC (*Chinese Simplified*) +- Rintan1 (*Japanese*) +- Antillion (*Spanish*) +- hiphipvargas (*Portuguese*) +- Ch. (*Korean*) +- tctovsli (*Norwegian Nynorsk*) +- vjasiegd (*Polish*) +- SamitiMed (*Thai*) +- umelard (*Hebrew*) +- 硫酸鶏 (*Japanese*) +- Adrián Lattes (*Spanish*) +- Hinaloe (*Japanese*) +- Renato "Lond" Cerqueira (*Portuguese, Brazilian*) +- parnikkapore (*Thai*) +- Marcin Mikołajczak (*Polish*) +- 森の子リスのミーコの大冒険 (*Japanese*) +- Marcepanek_ (*Polish*) +- Sahak Petrosyan (*Armenian*) +- Daniel Dimitrov (*Bulgarian*) +- Hugh Liu (*Chinese Simplified*) +- Rakino (*Chinese Simplified*) +- hussama (*Portuguese, Brazilian*) +- ThibG (*French*) +- SnDer (*Dutch*) +- PifyZ (*French*) +- eichkat3r (*German*) +- Karol Kosek (*Polish*) +- Akarshan Biswas (*Bengali*) +- Tradjincal (*French*) +- Steven Tappert (*German*) +- sergioaraujo1 (*Portuguese, Brazilian*) +- mmokhi (*Persian*) +- fedot (*Russian*) +- skaaarrr (*German*) +- JackXu (*Chinese Simplified*) +- Lukas Fülling (*German*) +- Zoé Bőle (*German*) +- Dremski (*Bulgarian*) +- tamaina (*Japanese*) +- OpenAlgeria (*Arabic*) From 6c9b4f6b7710cbbdafcceafb59dfef0be6baba65 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 05:05:02 +0200 Subject: [PATCH 20/38] Fix tootctl not allocating enough database connections for main thread (#12097) --- lib/mastodon/cli_helper.rb | 2 +- lib/mastodon/feeds_cli.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/mastodon/cli_helper.rb b/lib/mastodon/cli_helper.rb index c2950dffa3..ec4d9a81e5 100644 --- a/lib/mastodon/cli_helper.rb +++ b/lib/mastodon/cli_helper.rb @@ -20,7 +20,7 @@ module Mastodon exit(1) end - ActiveRecord::Base.configurations[Rails.env]['pool'] = options[:concurrency] + ActiveRecord::Base.configurations[Rails.env]['pool'] = options[:concurrency] + 1 progress = create_progress_bar(scope.count) pool = Concurrent::FixedThreadPool.new(options[:concurrency]) diff --git a/lib/mastodon/feeds_cli.rb b/lib/mastodon/feeds_cli.rb index ea7c90dffc..578ea15c58 100644 --- a/lib/mastodon/feeds_cli.rb +++ b/lib/mastodon/feeds_cli.rb @@ -27,7 +27,6 @@ module Mastodon dry_run = options[:dry_run] ? '(DRY RUN)' : '' if options[:all] || username.nil? - processed, = parallelize_with_progress(Account.joins(:user).merge(User.active)) do |account| PrecomputeFeedService.new.call(account) unless options[:dry_run] end From ebe574d5b57c647450cab3d4ca2e8ca52c4fb3fe Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 06:05:14 +0200 Subject: [PATCH 21/38] Fix old migration trying to use new column due to default status scope (#12095) Fix #12087 --- db/migrate/20181024224956_migrate_account_conversations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20181024224956_migrate_account_conversations.rb b/db/migrate/20181024224956_migrate_account_conversations.rb index b718f9e1d5..d4bc3b91d9 100644 --- a/db/migrate/20181024224956_migrate_account_conversations.rb +++ b/db/migrate/20181024224956_migrate_account_conversations.rb @@ -52,6 +52,6 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2] end def notifications_about_direct_statuses - Notification.joins(mention: :status).where(activity_type: 'Mention', statuses: { visibility: :direct }) + Notification.joins('INNER JOIN mentions ON mentions.id = notifications.activity_id INNER JOIN statuses ON statuses.id = mentions.status_id').where(activity_type: 'Mention', statuses: { visibility: :direct }) end end From 0aaa3afc2df2cc2fa8cdd277cf91dcfabf45afcd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Oct 2019 20:04:56 +0200 Subject: [PATCH 22/38] Add `tootctl media usage` command (#12115) --- lib/mastodon/media_cli.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/mastodon/media_cli.rb b/lib/mastodon/media_cli.rb index ec2f36c302..bb97751d58 100644 --- a/lib/mastodon/media_cli.rb +++ b/lib/mastodon/media_cli.rb @@ -97,5 +97,17 @@ module Mastodon say("Downloaded #{processed} media attachments (approx. #{number_to_human_size(aggregate)})#{dry_run}", :green, true) end + + desc 'usage', 'Calculate disk space consumed by Mastodon' + def usage + say("Attachments:\t#{number_to_human_size(MediaAttachment.sum(:file_file_size))} (#{number_to_human_size(MediaAttachment.where(account: Account.local).sum(:file_file_size))} local)") + say("Custom emoji:\t#{number_to_human_size(CustomEmoji.sum(:image_file_size))} (#{number_to_human_size(CustomEmoji.local.sum(:image_file_size))} local)") + say("Preview cards:\t#{number_to_human_size(PreviewCard.sum(:image_file_size))}") + say("Avatars:\t#{number_to_human_size(Account.sum(:avatar_file_size))} (#{number_to_human_size(Account.local.sum(:avatar_file_size))} local)") + say("Headers:\t#{number_to_human_size(Account.sum(:header_file_size))} (#{number_to_human_size(Account.local.sum(:header_file_size))} local)") + say("Backups:\t#{number_to_human_size(Backup.sum(:dump_file_size))}") + say("Imports:\t#{number_to_human_size(Import.sum(:data_file_size))}") + say("Settings:\t#{number_to_human_size(SiteUpload.sum(:file_file_size))}") + end end end From 4a98e77d0e7fec15e1830059a9a56bf56aa391db Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Oct 2019 05:59:10 +0200 Subject: [PATCH 23/38] Change `tootctl media refresh` to skip already downloaded attachments (#12118) --- lib/mastodon/media_cli.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/mastodon/media_cli.rb b/lib/mastodon/media_cli.rb index bb97751d58..e48175134c 100644 --- a/lib/mastodon/media_cli.rb +++ b/lib/mastodon/media_cli.rb @@ -50,6 +50,7 @@ module Mastodon option :concurrency, type: :numeric, default: 5, aliases: [:c] option :verbose, type: :boolean, default: false, aliases: [:v] option :dry_run, type: :boolean, default: false + option :force, type: :boolean, default: false desc 'refresh', 'Fetch remote media files' long_desc <<-DESC Re-downloads media attachments from other servers. You must specify the @@ -62,6 +63,9 @@ module Mastodon using username@domain handle of the account. Use the --domain option to download attachments from a specific domain. + + By default, attachments that are believed to be already downloaded will + not be re-downloaded. To force re-download of every URL, use --force. DESC def refresh dry_run = options[:dry_run] ? ' (DRY RUN)' : '' @@ -85,7 +89,7 @@ module Mastodon end processed, aggregate = parallelize_with_progress(scope) do |media_attachment| - next if media_attachment.remote_url.blank? + next if media_attachment.remote_url.blank? || (!options[:force] && media_attachment.file_file_name.present?) unless options[:dry_run] media_attachment.reset_file! From 19cdc627658166664fb1571ec45564d237e63757 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Oct 2019 22:08:55 +0200 Subject: [PATCH 24/38] Remove fallback to long description on sidebar and meta description (#12119) Fix #12114 --- app/views/about/show.html.haml | 13 ++++++------- app/views/application/_sidebar.html.haml | 2 +- app/views/shared/_og.html.haml | 2 +- config/locales/en.yml | 3 +-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml index f24f4e1957..80f4cd8287 100644 --- a/app/views/about/show.html.haml +++ b/app/views/about/show.html.haml @@ -52,13 +52,12 @@ .hero-widget__img = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title - - if @instance_presenter.site_short_description.present? - .hero-widget__text - %p - = @instance_presenter.site_short_description.html_safe.presence - = link_to about_more_path do - = t('about.learn_more') - = fa_icon 'angle-double-right' + .hero-widget__text + %p + = @instance_presenter.site_short_description.html_safe.presence || t('about.about_mastodon_html') + = link_to about_more_path do + = t('about.learn_more') + = fa_icon 'angle-double-right' .hero-widget__footer .hero-widget__footer__column diff --git a/app/views/application/_sidebar.html.haml b/app/views/application/_sidebar.html.haml index 33e7c96fe7..7ec91c06aa 100644 --- a/app/views/application/_sidebar.html.haml +++ b/app/views/application/_sidebar.html.haml @@ -3,7 +3,7 @@ = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title .hero-widget__text - %p= @instance_presenter.site_short_description.html_safe.presence || @instance_presenter.site_description.html_safe.presence || t('about.generic_description', domain: site_hostname) + %p= @instance_presenter.site_short_description.html_safe.presence || t('about.about_mastodon_html') - if Setting.trends && !(user_signed_in? && !current_user.setting_trends) - trends = TrendingTags.get(3) diff --git a/app/views/shared/_og.html.haml b/app/views/shared/_og.html.haml index 576f47a676..c8f12974e2 100644 --- a/app/views/shared/_og.html.haml +++ b/app/views/shared/_og.html.haml @@ -1,5 +1,5 @@ - thumbnail = @instance_presenter.thumbnail -- description ||= strip_tags(@instance_presenter.site_short_description.presence || @instance_presenter.site_description.presence || t('about.about_mastodon_html')) +- description ||= strip_tags(@instance_presenter.site_short_description.presence || t('about.about_mastodon_html')) %meta{ name: 'description', content: description }/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 4b9f2aab4e..68fc213231 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2,7 +2,7 @@ en: about: about_hashtag_html: These are public toots tagged with #%{hashtag}. You can interact with them if you have an account anywhere in the fediverse. - about_mastodon_html: Mastodon is a social network based on open web protocols and free, open-source software. It is decentralized like e-mail. + about_mastodon_html: 'The social network of the future: No ads, no corporate surveillance, ethical design, and decentralization! Own your data with Mastodon!' about_this: About active_count_after: active active_footnote: Monthly Active Users (MAU) @@ -18,7 +18,6 @@ en: discover_users: Discover users documentation: Documentation federation_hint_html: With an account on %{instance} you'll be able to follow people on any Mastodon server and beyond. - generic_description: "%{domain} is one server in the network" get_apps: Try a mobile app hosted_on: Mastodon hosted on %{domain} instance_actor_flash: | From c8bcf5cbfdc4b076eae0d9091e688436aa7f2508 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Oct 2019 00:30:15 +0200 Subject: [PATCH 25/38] Add admin setting to auto-approve hashtags (#12122) Change inaccurate labels on other admin settings --- app/models/form/admin_settings.rb | 2 ++ app/models/tag.rb | 2 +- app/views/admin/settings/edit.html.haml | 9 ++++++--- config/locales/en.yml | 11 +++++++---- config/settings.yml | 1 + 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 24196e1828..70e9c21f16 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -30,6 +30,7 @@ class Form::AdminSettings mascot spam_check_enabled trends + trendable_by_default show_domain_blocks show_domain_blocks_rationale noindex @@ -46,6 +47,7 @@ class Form::AdminSettings profile_directory spam_check_enabled trends + trendable_by_default noindex ).freeze diff --git a/app/models/tag.rb b/app/models/tag.rb index 82786daa81..59445a83b8 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -76,7 +76,7 @@ class Tag < ApplicationRecord alias listable? listable def trendable - boolean_with_default('trendable', false) + boolean_with_default('trendable', Setting.trendable_by_default) end alias trendable? trendable diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml index 752386b3ca..6282bb39c0 100644 --- a/app/views/admin/settings/edit.html.haml +++ b/app/views/admin/settings/edit.html.haml @@ -20,10 +20,10 @@ = f.input :site_contact_email, wrapper: :with_label, label: t('admin.settings.contact_information.email') .fields-group - = f.input :site_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description.title'), hint: t('admin.settings.site_description.desc_html'), input_html: { rows: 4 } + = f.input :site_short_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_short_description.title'), hint: t('admin.settings.site_short_description.desc_html'), input_html: { rows: 2 } .fields-group - = f.input :site_short_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_short_description.title'), hint: t('admin.settings.site_short_description.desc_html'), input_html: { rows: 2 } + = f.input :site_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description.title'), hint: t('admin.settings.site_description.desc_html'), input_html: { rows: 2 } .fields-row .fields-row__column.fields-row__column-6.fields-group @@ -71,6 +71,9 @@ .fields-group = f.input :trends, as: :boolean, wrapper: :with_label, label: t('admin.settings.trends.title'), hint: t('admin.settings.trends.desc_html') + .fields-group + = f.input :trendable_by_default, as: :boolean, wrapper: :with_label, label: t('admin.settings.trendable_by_default.title'), hint: t('admin.settings.trendable_by_default.desc_html') + .fields-group = f.input :noindex, as: :boolean, wrapper: :with_label, label: t('admin.settings.default_noindex.title'), hint: t('admin.settings.default_noindex.desc_html') @@ -89,8 +92,8 @@ = f.input :show_domain_blocks_rationale, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks_rationale.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' .fields-group - = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 } = f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 } unless whitelist_mode? + = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 } = f.input :site_terms, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_terms.title'), hint: t('admin.settings.site_terms.desc_html'), input_html: { rows: 8 } = f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 }, label: t('admin.settings.custom_css.title'), hint: t('admin.settings.custom_css.desc_html') diff --git a/config/locales/en.yml b/config/locales/en.yml index 68fc213231..0e8ee6a765 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -478,8 +478,8 @@ en: open: Anyone can sign up title: Registrations mode show_known_fediverse_at_about_page: - desc_html: When toggled, it will show toots from all the known fediverse on preview. Otherwise it will only show local toots. - title: Show known fediverse on timeline preview + desc_html: When disabled, restricts the public timeline linked from the landing page to showing only local content + title: Include federated content on unauthenticated public timeline page show_staff_badge: desc_html: Show a staff badge on a user page title: Show staff badge @@ -503,9 +503,12 @@ en: desc_html: Used for previews via OpenGraph and API. 1200x630px recommended title: Server thumbnail timeline_preview: - desc_html: Display public timeline on landing page - title: Timeline preview + desc_html: Display link to public timeline on landing page and allow API access to the public timeline without authentication + title: Allow unauthenticated access to public timeline title: Site settings + trendable_by_default: + desc_html: Affects hashtags that have not been previously disallowed + title: Allow hashtags to trend without prior review trends: desc_html: Publicly display previously reviewed hashtags that are currently trending title: Trending hashtags diff --git a/config/settings.yml b/config/settings.yml index 6dbc46706a..bd2f65b5e4 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -35,6 +35,7 @@ defaults: &defaults use_blurhash: true use_pending_items: false trends: true + trendable_by_default: false notification_emails: follow: false reblog: false From 538db85d3cc6d8fcb3c0a89f7eef069a686c19f4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Oct 2019 03:45:05 +0200 Subject: [PATCH 26/38] Remove `lang` attribute from individual statuses (#12124) Fix #10930 --- app/javascript/mastodon/components/status_content.js | 8 ++++---- app/views/statuses/_detailed_status.html.haml | 2 +- app/views/statuses/_simple_status.html.haml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index c171e7a66f..4ce9ec49f3 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -216,14 +216,14 @@ export default class StatusContent extends React.PureComponent { return (
{mentionsPlaceholder} -
+
{!hidden && !!status.get('poll') && }
@@ -231,7 +231,7 @@ export default class StatusContent extends React.PureComponent { } else if (this.props.onClick) { const output = [
-
+
{!!status.get('poll') && }
, @@ -245,7 +245,7 @@ export default class StatusContent extends React.PureComponent { } else { return (
-
+
{!!status.get('poll') && }
diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index 12f03ccdde..5cee84ada8 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -20,7 +20,7 @@ %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }< %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}  %button.status__content__spoiler-link= t('statuses.show_more') - .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" } + .e-content{ style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" } = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) - if status.preloadable_poll = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index ca3c8fdd5c..a68fe10220 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -24,7 +24,7 @@ %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }< %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}  %button.status__content__spoiler-link= t('statuses.show_more') - .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" } + .e-content{ style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" } = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) - if status.preloadable_poll = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do From 354fdd317e9c495ed721013911bc5274d5e0e1f8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Oct 2019 07:10:46 +0200 Subject: [PATCH 27/38] Fix attachment not being re-downloaded even if file is not stored (#12125) Change the behaviour of remotable concern. Previously, it would skip downloading an attachment if the stored remote URL is identical to the new one. Now it would not be skipped if the attachment is not actually currently stored by Paperclip. --- .../api/v1/streaming_controller.rb | 14 ++++++++++---- app/models/account.rb | 7 +++---- app/models/concerns/remotable.rb | 2 +- config/initializers/paperclip.rb | 19 +++++++++++++------ spec/models/account_spec.rb | 4 ++-- spec/models/concerns/remotable_spec.rb | 13 ++++++++++++- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/app/controllers/api/v1/streaming_controller.rb b/app/controllers/api/v1/streaming_controller.rb index 66b812e761..ebb17608c1 100644 --- a/app/controllers/api/v1/streaming_controller.rb +++ b/app/controllers/api/v1/streaming_controller.rb @@ -5,11 +5,17 @@ class Api::V1::StreamingController < Api::BaseController def index if Rails.configuration.x.streaming_api_base_url != request.host - uri = URI.parse(request.url) - uri.host = URI.parse(Rails.configuration.x.streaming_api_base_url).host - redirect_to uri.to_s, status: 301 + redirect_to streaming_api_url, status: 301 else - raise ActiveRecord::RecordNotFound + not_found end end + + private + + def streaming_api_url + Addressable::URI.parse(request.url).tap do |uri| + uri.host = Addressable::URI.parse(Rails.configuration.x.streaming_api_base_url).host + end.to_s + end end diff --git a/app/models/account.rb b/app/models/account.rb index 01d45e36c2..2f43f337fc 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -310,10 +310,9 @@ class Account < ApplicationRecord def save_with_optional_media! save! rescue ActiveRecord::RecordInvalid - self.avatar = nil - self.header = nil - self[:avatar_remote_url] = '' - self[:header_remote_url] = '' + self.avatar = nil + self.header = nil + save! end diff --git a/app/models/concerns/remotable.rb b/app/models/concerns/remotable.rb index 0823026193..b7a476c87a 100644 --- a/app/models/concerns/remotable.rb +++ b/app/models/concerns/remotable.rb @@ -18,7 +18,7 @@ module Remotable return end - return if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.blank? || self[attribute_name] == url + return if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.blank? || (self[attribute_name] == url && send("#{attachment_name}_file_name").present?) begin Request.new(:get, url).perform do |response| diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index a0253f4bc0..d3602e655e 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true -Paperclip.options[:read_timeout] = 60 - Paperclip.interpolates :filename do |attachment, style| - return attachment.original_filename if style == :original - [basename(attachment, style), extension(attachment, style)].delete_if(&:blank?).join('.') + if style == :original + attachment.original_filename + else + [basename(attachment, style), extension(attachment, style)].delete_if(&:blank?).join('.') + end end Paperclip::Attachment.default_options.merge!( @@ -24,17 +25,21 @@ if ENV['S3_ENABLED'] == 'true' storage: :s3, s3_protocol: s3_protocol, s3_host_name: s3_hostname, + s3_headers: { 'X-Amz-Multipart-Threshold' => ENV.fetch('S3_MULTIPART_THRESHOLD') { 15.megabytes }.to_i, 'Cache-Control' => 'public, max-age=315576000, immutable', }, + s3_permissions: ENV.fetch('S3_PERMISSION') { 'public-read' }, s3_region: s3_region, + s3_credentials: { bucket: ENV['S3_BUCKET'], access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], }, + s3_options: { signature_version: ENV.fetch('S3_SIGNATURE_VERSION') { 'v4' }, http_open_timeout: 5, @@ -49,6 +54,7 @@ if ENV['S3_ENABLED'] == 'true' endpoint: ENV['S3_ENDPOINT'], force_path_style: true ) + Paperclip::Attachment.default_options[:url] = ':s3_path_url' end @@ -74,6 +80,7 @@ elsif ENV['SWIFT_ENABLED'] == 'true' openstack_region: ENV['SWIFT_REGION'], openstack_cache_ttl: ENV.fetch('SWIFT_CACHE_TTL') { 60 }, }, + fog_directory: ENV['SWIFT_CONTAINER'], fog_host: ENV['SWIFT_OBJECT_URL'], fog_public: true @@ -82,7 +89,7 @@ else Paperclip::Attachment.default_options.merge!( storage: :filesystem, use_timestamp: true, - path: (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + '/:class/:attachment/:id_partition/:style/:filename', - url: (ENV['PAPERCLIP_ROOT_URL'] || '/system') + '/:class/:attachment/:id_partition/:style/:filename', + path: ENV.fetch('PAPERCLIP_ROOT_PATH', ':rails_root/public/system') + '/:class/:attachment/:id_partition/:style/:filename', + url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:class/:attachment/:id_partition/:style/:filename', ) end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 3eec464bd3..b2f6234cb9 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -126,8 +126,8 @@ RSpec.describe Account, type: :model do end it 'sets default avatar, header, avatar_remote_url, and header_remote_url' do - expect(account.avatar_remote_url).to eq '' - expect(account.header_remote_url).to eq '' + expect(account.avatar_remote_url).to eq 'https://remote.test/invalid_avatar' + expect(account.header_remote_url).to eq expectation.header_remote_url expect(account.avatar_file_name).to eq nil expect(account.header_file_name).to eq nil end diff --git a/spec/models/concerns/remotable_spec.rb b/spec/models/concerns/remotable_spec.rb index a4289cc45e..99a60cbf65 100644 --- a/spec/models/concerns/remotable_spec.rb +++ b/spec/models/concerns/remotable_spec.rb @@ -18,6 +18,8 @@ RSpec.describe Remotable do def hoge=(arg); end + def hoge_file_name; end + def hoge_file_name=(arg); end def has_attribute?(arg); end @@ -109,12 +111,21 @@ RSpec.describe Remotable do end context 'foo[attribute_name] == url' do - it 'makes no request' do + it 'makes no request if file is saved' do allow(foo).to receive(:[]).with(attribute_name).and_return(url) + allow(foo).to receive(:hoge_file_name).and_return('foo.jpg') foo.hoge_remote_url = url expect(request).not_to have_been_requested end + + it 'makes request if file is not saved' do + allow(foo).to receive(:[]).with(attribute_name).and_return(url) + allow(foo).to receive(:hoge_file_name).and_return(nil) + + foo.hoge_remote_url = url + expect(request).to have_been_requested + end end context "scheme is https, parsed_url.host isn't empty, and foo[attribute_name] != url" do From b5f7e12817356b9b1795ab0187fe08d07f13a485 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Oct 2019 07:11:23 +0200 Subject: [PATCH 28/38] Remove auto-silence behaviour from spam check (#12117) Fix #12113 --- app/lib/spam_check.rb | 7 +------ app/models/account.rb | 2 +- app/models/admin/account_action.rb | 12 ++++++++++++ config/locales/en.yml | 2 +- spec/lib/spam_check_spec.rb | 4 ---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/lib/spam_check.rb b/app/lib/spam_check.rb index 441697364f..235e442309 100644 --- a/app/lib/spam_check.rb +++ b/app/lib/spam_check.rb @@ -44,7 +44,6 @@ class SpamCheck end def flag! - auto_silence_account! auto_report_status! end @@ -134,17 +133,13 @@ class SpamCheck text.gsub(/\s+/, ' ').strip end - def auto_silence_account! - @account.silence! - end - def auto_report_status! status_ids = Status.where(visibility: %i(public unlisted)).where(id: matching_status_ids).pluck(:id) + [@status.id] if @status.distributable? ReportService.new.call(Account.representative, @account, status_ids: status_ids, comment: I18n.t('spam_check.spam_detected_and_silenced')) end def already_flagged? - @account.silenced? + @account.silenced? || @account.targeted_reports.unresolved.where(account_id: -99).exists? end def trusted? diff --git a/app/models/account.rb b/app/models/account.rb index 2f43f337fc..05936def32 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -198,7 +198,7 @@ class Account < ApplicationRecord end def unsilence! - update!(silenced_at: nil, trust_level: trust_level == TRUST_LEVELS[:untrusted] ? TRUST_LEVELS[:trusted] : trust_level) + update!(silenced_at: nil) end def suspended? diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index b30a823699..e9da003a30 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -62,6 +62,8 @@ class Admin::AccountAction def process_action! case type + when 'none' + handle_resolve! when 'disable' handle_disable! when 'silence' @@ -103,6 +105,16 @@ class Admin::AccountAction end end + def handle_resolve! + if with_report? && report.account_id == -99 && target_account.trust_level == Account::TRUST_LEVELS[:untrusted] + # This is an automated report and it is being dismissed, so it's + # a false positive, in which case update the account's trust level + # to prevent further spam checks + + target_account.update(trust_level: Account::TRUST_LEVELS[:trusted]) + end + end + def handle_disable! authorize(target_account.user, :disable?) log_action(:disable, target_account.user) diff --git a/config/locales/en.yml b/config/locales/en.yml index 0e8ee6a765..1ffc99eb3d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -497,7 +497,7 @@ en: title: Custom terms of service site_title: Server name spam_check_enabled: - desc_html: Mastodon can auto-silence and auto-report accounts that send repeated unsolicited messages. There may be false positives. + desc_html: Mastodon can auto-report accounts that send repeated unsolicited messages. There may be false positives. title: Anti-spam automation thumbnail: desc_html: Used for previews via OpenGraph and API. 1200x630px recommended diff --git a/spec/lib/spam_check_spec.rb b/spec/lib/spam_check_spec.rb index 4cae461117..d4d66a4993 100644 --- a/spec/lib/spam_check_spec.rb +++ b/spec/lib/spam_check_spec.rb @@ -181,10 +181,6 @@ RSpec.describe SpamCheck do described_class.new(status2).flag! end - it 'silences the account' do - expect(sender.silenced?).to be true - end - it 'creates a report about the account' do expect(sender.targeted_reports.unresolved.count).to eq 1 end From e6d111f38b95b08a2880390b1519655b54ac2fd0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 9 Oct 2019 07:36:57 +0200 Subject: [PATCH 29/38] Bump version to 3.0.1 (#12116) --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ lib/mastodon/version.rb | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b0d23a22c..47a4662942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,36 @@ Changelog All notable changes to this project will be documented in this file. +## [3.0.1] - 2019-10-09 +### Added + +- Add `tootctl media usage` command ([Gargron](https://github.com/tootsuite/mastodon/pull/12115)) +- Add admin setting to auto-approve trending hashtags ([Gargron](https://github.com/tootsuite/mastodon/pull/12122)) + +### Changed + +- Change `tootctl media refresh` to skip already downloaded attachments ([Gargron](https://github.com/tootsuite/mastodon/pull/12118)) + +### Removed + +- Remove auto-silence behaviour from spam check ([Gargron](https://github.com/tootsuite/mastodon/pull/12117)) +- Remove HTML `lang` attribute from individual statuses in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12124)) +- Remove fallback to long description on sidebar and meta description ([Gargron](https://github.com/tootsuite/mastodon/pull/12119)) + +### Fixed + +- Fix attachment not being re-downloaded even if file is not stored ([Gargron](https://github.com/tootsuite/mastodon/pull/12125)) +- Fix old migration trying to use new column due to default status scope ([Gargron](https://github.com/tootsuite/mastodon/pull/12095)) +- Fix column back button missing for not found accounts ([trwnh](https://github.com/tootsuite/mastodon/pull/12094)) +- Fix issues with tootctl's parallelization and progress reporting ([Gargron](https://github.com/tootsuite/mastodon/pull/12093), [Gargron](https://github.com/tootsuite/mastodon/pull/12097)) +- Fix existing user records with now-renamed `pt` locale ([Gargron](https://github.com/tootsuite/mastodon/pull/12092)) +- Fix hashtag timeline REST API accepting too many hashtags ([Gargron](https://github.com/tootsuite/mastodon/pull/12091)) +- Fix `GET /api/v1/instance` REST APIs being unavailable in secure mode ([Gargron](https://github.com/tootsuite/mastodon/pull/12089)) +- Fix performance of home feed regeneration and merging ([Gargron](https://github.com/tootsuite/mastodon/pull/12084)) +- Fix ffmpeg performance issues due to stdout buffer overflow ([hugogameiro](https://github.com/tootsuite/mastodon/pull/12088)) +- Fix S3 adapter retrying failing uploads with exponential backoff ([Gargron](https://github.com/tootsuite/mastodon/pull/12085)) +- Fix `tootctl accounts cull` advertising unused option flag ([Kjwon15](https://github.com/tootsuite/mastodon/pull/12074)) + ## [3.0.0] - 2019-10-03 ### Added diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index a0f4678ec5..f3ead6d8d9 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 0 + 1 end def flags From 30a28a2eb7bdd39de877ae8171555307986b3e06 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 10 Oct 2019 02:21:52 +0200 Subject: [PATCH 30/38] Fix not showing if emoji has a local counterpart in admin UI (#12135) Fix #12132 --- app/views/admin/custom_emojis/_custom_emoji.html.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/admin/custom_emojis/_custom_emoji.html.haml b/app/views/admin/custom_emojis/_custom_emoji.html.haml index 2103b0fa7d..526c844e92 100644 --- a/app/views/admin/custom_emojis/_custom_emoji.html.haml +++ b/app/views/admin/custom_emojis/_custom_emoji.html.haml @@ -17,6 +17,10 @@ - else = custom_emoji.domain + - if custom_emoji.local_counterpart.present? + • + = t('admin.accounts.location.local') + %br/ - if custom_emoji.disabled? From 915f3712ae7ae44c0cbe50c9694c25e3ee87a540 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 10 Oct 2019 02:22:04 +0200 Subject: [PATCH 31/38] Fix admin setting to auto-approve hashtags not affecting query (#12130) Follow-up to #12122 --- app/models/tag.rb | 1 + app/models/trending_tags.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/tag.rb b/app/models/tag.rb index 59445a83b8..d3a7e1e6d4 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -37,6 +37,7 @@ class Tag < ApplicationRecord scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) } scope :usable, -> { where(usable: [true, nil]) } scope :listable, -> { where(listable: [true, nil]) } + scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) } scope :discoverable, -> { listable.joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) } scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) } scope :matches_name, ->(value) { where(arel_table[:name].matches("#{value}%")) } diff --git a/app/models/trending_tags.rb b/app/models/trending_tags.rb index 8cdade42d4..c69f6d3c33 100644 --- a/app/models/trending_tags.rb +++ b/app/models/trending_tags.rb @@ -90,7 +90,7 @@ class TrendingTags tag_ids = redis.zrevrange(KEY, 0, LIMIT - 1).map(&:to_i) tags = Tag.where(id: tag_ids) - tags = tags.where(trendable: true) if filtered + tags = tags.trendable if filtered tags = tags.each_with_object({}) { |tag, h| h[tag.id] = tag } tag_ids.map { |tag_id| tags[tag_id] }.compact.take(limit) From 6ebd74f4fa640b9616ebb2730d97722799c6ed56 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 10 Oct 2019 05:21:38 +0200 Subject: [PATCH 32/38] Fix media editing modal changing dimensions when image loads (#12131) --- .../components/extended_video_player.js | 63 ---------------- app/javascript/mastodon/components/gifv.js | 75 +++++++++++++++++++ .../ui/components/focal_point_modal.js | 36 ++++++++- .../features/ui/components/media_modal.js | 6 +- .../styles/mastodon/components.scss | 3 +- 5 files changed, 113 insertions(+), 70 deletions(-) delete mode 100644 app/javascript/mastodon/components/extended_video_player.js create mode 100644 app/javascript/mastodon/components/gifv.js diff --git a/app/javascript/mastodon/components/extended_video_player.js b/app/javascript/mastodon/components/extended_video_player.js deleted file mode 100644 index 009c0d559a..0000000000 --- a/app/javascript/mastodon/components/extended_video_player.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class ExtendedVideoPlayer extends React.PureComponent { - - static propTypes = { - src: PropTypes.string.isRequired, - alt: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number, - time: PropTypes.number, - controls: PropTypes.bool.isRequired, - muted: PropTypes.bool.isRequired, - onClick: PropTypes.func, - }; - - handleLoadedData = () => { - if (this.props.time) { - this.video.currentTime = this.props.time; - } - } - - componentDidMount () { - this.video.addEventListener('loadeddata', this.handleLoadedData); - } - - componentWillUnmount () { - this.video.removeEventListener('loadeddata', this.handleLoadedData); - } - - setRef = (c) => { - this.video = c; - } - - handleClick = e => { - e.stopPropagation(); - const handler = this.props.onClick; - if (handler) handler(); - } - - render () { - const { src, muted, controls, alt } = this.props; - - return ( -
-
- ); - } - -} diff --git a/app/javascript/mastodon/components/gifv.js b/app/javascript/mastodon/components/gifv.js new file mode 100644 index 0000000000..83cfae49c4 --- /dev/null +++ b/app/javascript/mastodon/components/gifv.js @@ -0,0 +1,75 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class GIFV extends React.PureComponent { + + static propTypes = { + src: PropTypes.string.isRequired, + alt: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + onClick: PropTypes.func, + }; + + state = { + loading: true, + }; + + handleLoadedData = () => { + this.setState({ loading: false }); + } + + componentWillReceiveProps (nextProps) { + if (nextProps.src !== this.props.src) { + this.setState({ loading: true }); + } + } + + handleClick = e => { + const { onClick } = this.props; + + if (onClick) { + e.stopPropagation(); + onClick(); + } + } + + render () { + const { src, width, height, alt } = this.props; + const { loading } = this.state; + + return ( +
+ {loading && ( + + )} + +
+ ); + } + +} diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js index 1ab79a21df..3694ab9046 100644 --- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js +++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js @@ -16,6 +16,7 @@ import UploadProgress from 'mastodon/features/compose/components/upload_progress import CharacterCounter from 'mastodon/features/compose/components/character_counter'; import { length } from 'stringz'; import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components'; +import GIFV from 'mastodon/components/gifv'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -41,6 +42,36 @@ const removeExtraLineBreaks = str => str.replace(/\n\n/g, '******') const assetHost = process.env.CDN_HOST || ''; +class ImageLoader extends React.PureComponent { + + static propTypes = { + src: PropTypes.string.isRequired, + width: PropTypes.number, + height: PropTypes.number, + }; + + state = { + loading: true, + }; + + componentDidMount() { + const image = new Image(); + image.addEventListener('load', () => this.setState({ loading: false })); + image.src = this.props.src; + } + + render () { + const { loading } = this.state; + + if (loading) { + return ; + } else { + return ; + } + } + +} + export default @connect(mapStateToProps, mapDispatchToProps) @injectIntl class FocalPointModal extends ImmutablePureComponent { @@ -60,6 +91,7 @@ class FocalPointModal extends ImmutablePureComponent { description: '', dirty: false, progress: 0, + loading: true, }; componentWillMount () { @@ -242,8 +274,8 @@ class FocalPointModal extends ImmutablePureComponent {
{focals && (
- {media.get('type') === 'image' && } - {media.get('type') === 'gifv' &&