Browse Source

Merge tag 'v3.0.1'

Mike Barnes 3 weeks ago
parent
commit
87de0ed9e1
100 changed files with 2198 additions and 1387 deletions
  1. 12
    10
      .circleci/config.yml
  2. 41
    15
      .env.nanobox
  3. 16
    1
      .env.production.sample
  4. 1
    1
      .ruby-version
  5. 244
    426
      AUTHORS.md
  6. 229
    0
      CHANGELOG.md
  7. 9
    11
      Dockerfile
  8. 31
    24
      Gemfile
  9. 165
    124
      Gemfile.lock
  10. 1
    1
      README.md
  11. 0
    9
      app.json
  12. 43
    0
      app/chewy/accounts_index.rb
  13. 5
    5
      app/chewy/statuses_index.rb
  14. 37
    0
      app/chewy/tags_index.rb
  15. 40
    8
      app/controllers/about_controller.rb
  16. 37
    18
      app/controllers/accounts_controller.rb
  17. 11
    0
      app/controllers/activitypub/base_controller.rb
  18. 8
    17
      app/controllers/activitypub/collections_controller.rb
  19. 19
    16
      app/controllers/activitypub/inboxes_controller.rb
  20. 4
    8
      app/controllers/activitypub/outboxes_controller.rb
  21. 71
    0
      app/controllers/activitypub/replies_controller.rb
  22. 2
    2
      app/controllers/admin/account_actions_controller.rb
  23. 3
    15
      app/controllers/admin/accounts_controller.rb
  24. 34
    68
      app/controllers/admin/custom_emojis_controller.rb
  25. 15
    3
      app/controllers/admin/dashboard_controller.rb
  26. 40
    0
      app/controllers/admin/domain_allows_controller.rb
  27. 26
    2
      app/controllers/admin/domain_blocks_controller.rb
  28. 27
    3
      app/controllers/admin/instances_controller.rb
  29. 6
    1
      app/controllers/admin/relays_controller.rb
  30. 4
    5
      app/controllers/admin/report_notes_controller.rb
  31. 77
    18
      app/controllers/admin/tags_controller.rb
  32. 1
    0
      app/controllers/admin/two_factor_authentications_controller.rb
  33. 20
    1
      app/controllers/api/base_controller.rb
  34. 4
    13
      app/controllers/api/proofs_controller.rb
  35. 0
    73
      app/controllers/api/push_controller.rb
  36. 0
    37
      app/controllers/api/salmon_controller.rb
  37. 0
    51
      app/controllers/api/subscriptions_controller.rb
  38. 3
    2
      app/controllers/api/v1/accounts/statuses_controller.rb
  39. 4
    2
      app/controllers/api/v1/accounts_controller.rb
  40. 1
    1
      app/controllers/api/v1/admin/accounts_controller.rb
  41. 2
    0
      app/controllers/api/v1/apps_controller.rb
  42. 2
    3
      app/controllers/api/v1/custom_emojis_controller.rb
  43. 30
    0
      app/controllers/api/v1/directories_controller.rb
  44. 20
    0
      app/controllers/api/v1/featured_tags/suggestions_controller.rb
  45. 40
    0
      app/controllers/api/v1/featured_tags_controller.rb
  46. 6
    2
      app/controllers/api/v1/follow_requests_controller.rb
  47. 0
    31
      app/controllers/api/v1/follows_controller.rb
  48. 5
    2
      app/controllers/api/v1/instances/activity_controller.rb
  49. 5
    2
      app/controllers/api/v1/instances/peers_controller.rb
  50. 4
    3
      app/controllers/api/v1/instances_controller.rb
  51. 44
    0
      app/controllers/api/v1/markers_controller.rb
  52. 1
    1
      app/controllers/api/v1/reports_controller.rb
  53. 0
    32
      app/controllers/api/v1/search_controller.rb
  54. 2
    1
      app/controllers/api/v1/statuses/reblogs_controller.rb
  55. 4
    13
      app/controllers/api/v1/statuses_controller.rb
  56. 10
    4
      app/controllers/api/v1/streaming_controller.rb
  57. 0
    63
      app/controllers/api/v1/timelines/direct_controller.rb
  58. 1
    5
      app/controllers/api/v1/timelines/home_controller.rb
  59. 5
    0
      app/controllers/api/v1/timelines/public_controller.rb
  60. 17
    0
      app/controllers/api/v1/trends_controller.rb
  61. 26
    2
      app/controllers/api/v2/search_controller.rb
  62. 34
    47
      app/controllers/application_controller.rb
  63. 22
    0
      app/controllers/auth/challenges_controller.rb
  64. 18
    14
      app/controllers/auth/confirmations_controller.rb
  65. 1
    1
      app/controllers/auth/omniauth_callbacks_controller.rb
  66. 8
    1
      app/controllers/auth/registrations_controller.rb
  67. 15
    10
      app/controllers/auth/sessions_controller.rb
  68. 58
    0
      app/controllers/auth/setup_controller.rb
  69. 4
    32
      app/controllers/concerns/account_controller_concern.rb
  70. 34
    0
      app/controllers/concerns/account_owned_concern.rb
  71. 50
    0
      app/controllers/concerns/cache_concern.rb
  72. 65
    0
      app/controllers/concerns/challengable_concern.rb
  73. 7
    0
      app/controllers/concerns/export_controller_concern.rb
  74. 32
    2
      app/controllers/concerns/signature_verification.rb
  75. 87
    0
      app/controllers/concerns/status_controller_concern.rb
  76. 2
    0
      app/controllers/custom_css_controller.rb
  77. 8
    9
      app/controllers/directories_controller.rb
  78. 2
    3
      app/controllers/emojis_controller.rb
  79. 13
    4
      app/controllers/follower_accounts_controller.rb
  80. 13
    4
      app/controllers/following_accounts_controller.rb
  81. 3
    19
      app/controllers/home_controller.rb
  82. 22
    0
      app/controllers/instance_actors_controller.rb
  83. 1
    0
      app/controllers/intents_controller.rb
  84. 1
    1
      app/controllers/invites_controller.rb
  85. 3
    1
      app/controllers/manifests_controller.rb
  86. 2
    1
      app/controllers/media_controller.rb
  87. 7
    0
      app/controllers/media_proxy_controller.rb
  88. 2
    0
      app/controllers/oauth/authorized_applications_controller.rb
  89. 5
    13
      app/controllers/public_timelines_controller.rb
  90. 5
    11
      app/controllers/remote_follow_controller.rb
  91. 4
    2
      app/controllers/remote_interaction_controller.rb
  92. 0
    39
      app/controllers/remote_unfollows_controller.rb
  93. 43
    0
      app/controllers/settings/aliases_controller.rb
  94. 26
    6
      app/controllers/settings/deletes_controller.rb
  95. 7
    0
      app/controllers/settings/exports_controller.rb
  96. 45
    0
      app/controllers/settings/migration/redirects_controller.rb
  97. 28
    11
      app/controllers/settings/migrations_controller.rb
  98. 4
    1
      app/controllers/settings/preferences_controller.rb
  99. 2
    0
      app/controllers/settings/sessions_controller.rb
  100. 0
    0
      app/controllers/settings/two_factor_authentication/confirmations_controller.rb

+ 12
- 10
.circleci/config.yml View File

@@ -3,7 +3,7 @@ version: 2
3 3
 aliases:
4 4
   - &defaults
5 5
     docker:
6
-      - image: circleci/ruby:2.6.0-stretch-node
6
+      - image: circleci/ruby:2.6-stretch-node
7 7
         environment: &ruby_environment
8 8
           BUNDLE_APP_CONFIG: ./.bundle/
9 9
           DB_HOST: localhost
@@ -105,14 +105,14 @@ jobs:
105 105
   install-ruby2.5:
106 106
     <<: *defaults
107 107
     docker:
108
-      - image: circleci/ruby:2.5.3-stretch-node
108
+      - image: circleci/ruby:2.5-stretch-node
109 109
         environment: *ruby_environment
110 110
     <<: *install_ruby_dependencies
111 111
 
112 112
   install-ruby2.4:
113 113
     <<: *defaults
114 114
     docker:
115
-      - image: circleci/ruby:2.4.5-stretch-node
115
+      - image: circleci/ruby:2.4-stretch-node
116 116
         environment: *ruby_environment
117 117
     <<: *install_ruby_dependencies
118 118
 
@@ -131,40 +131,40 @@ jobs:
131 131
   test-ruby2.6:
132 132
     <<: *defaults
133 133
     docker:
134
-      - image: circleci/ruby:2.6.0-stretch-node
134
+      - image: circleci/ruby:2.6-stretch-node
135 135
         environment: *ruby_environment
136 136
       - image: circleci/postgres:10.6-alpine
137 137
         environment:
138 138
           POSTGRES_USER: root
139
-      - image: circleci/redis:5.0.3-alpine3.8
139
+      - image: circleci/redis:5-alpine
140 140
     <<: *test_steps
141 141
 
142 142
   test-ruby2.5:
143 143
     <<: *defaults
144 144
     docker:
145
-      - image: circleci/ruby:2.5.3-stretch-node
145
+      - image: circleci/ruby:2.5-stretch-node
146 146
         environment: *ruby_environment
147 147
       - image: circleci/postgres:10.6-alpine
148 148
         environment:
149 149
           POSTGRES_USER: root
150
-      - image: circleci/redis:4.0.12-alpine
150
+      - image: circleci/redis:5-alpine
151 151
     <<: *test_steps
152 152
 
153 153
   test-ruby2.4:
154 154
     <<: *defaults
155 155
     docker:
156
-      - image: circleci/ruby:2.4.5-stretch-node
156
+      - image: circleci/ruby:2.4-stretch-node
157 157
         environment: *ruby_environment
158 158
       - image: circleci/postgres:10.6-alpine
159 159
         environment:
160 160
           POSTGRES_USER: root
161
-      - image: circleci/redis:4.0.12-alpine
161
+      - image: circleci/redis:5-alpine
162 162
     <<: *test_steps
163 163
 
164 164
   test-webui:
165 165
     <<: *defaults
166 166
     docker:
167
-      - image: circleci/node:8.15.0-stretch
167
+      - image: circleci/node:12.9-stretch
168 168
     steps:
169 169
       - *attach_workspace
170 170
       - run: ./bin/retry yarn test:jest
@@ -173,9 +173,11 @@ jobs:
173 173
     <<: *defaults
174 174
     steps:
175 175
       - *attach_workspace
176
+      - *install_system_dependencies
176 177
       - run: bundle exec i18n-tasks check-normalized
177 178
       - run: bundle exec i18n-tasks unused -l en
178 179
       - run: bundle exec i18n-tasks check-consistent-interpolations
180
+      - run: bundle exec rake repo:check_locales_files
179 181
 
180 182
 workflows:
181 183
   version: 2

+ 41
- 15
.env.nanobox View File

@@ -11,24 +11,14 @@ DB_NAME=gonano
11 11
 DB_PASS=$DATA_DB_PASS
12 12
 DB_PORT=5432
13 13
 
14
-DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano
14
+# DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano
15 15
 
16 16
 # Optional ElasticSearch configuration
17 17
 ES_ENABLED=true
18 18
 ES_HOST=$DATA_ELASTIC_HOST
19 19
 ES_PORT=9200
20 20
 
21
-# Optimizations
22
-LD_PRELOAD=/data/lib/libjemalloc.so
23
-
24
-# ImageMagick optimizations
25
-MAGICK_TEMPORARY_PATH=/app/tmp
26
-MAGICK_MEMORY_LIMIT=128MiB
27
-MAGICK_MAP_LIMIT=64MiB
28
-MAGICK_TIME_LIMIT=15
29
-MAGICK_AREA_LIMIT=16MP
30
-MAGICK_WIDTH_LIMIT=8KP
31
-MAGICK_HEIGHT_LIMIT=8KP
21
+BIND=0.0.0.0
32 22
 
33 23
 # Federation
34 24
 # Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation.
@@ -84,6 +74,7 @@ SMTP_PORT=587
84 74
 SMTP_LOGIN=$SMTP_LOGIN
85 75
 SMTP_PASSWORD=$SMTP_PASSWORD
86 76
 SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
77
+#SMTP_REPLY_TO=
87 78
 #SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
88 79
 #SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
89 80
 #SMTP_AUTH_METHOD=plain
@@ -97,9 +88,17 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
97 88
 # PAPERCLIP_ROOT_URL=/system
98 89
 
99 90
 # Optional asset host for multi-server setups
91
+# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN
92
+# if WEB_DOMAIN is not set. For example, the server may have the
93
+# following header field:
94
+# Access-Control-Allow-Origin: https://example.com/
100 95
 # CDN_HOST=https://assets.example.com
101 96
 
102 97
 # S3 (optional)
98
+# The attachment host must allow cross origin request from WEB_DOMAIN or
99
+# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the
100
+# following header field:
101
+# Access-Control-Allow-Origin: https://192.168.1.123:9000/
103 102
 # S3_ENABLED=true
104 103
 # S3_BUCKET=
105 104
 # AWS_ACCESS_KEY_ID=
@@ -109,6 +108,8 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
109 108
 # S3_HOSTNAME=192.168.1.123:9000
110 109
 
111 110
 # S3 (Minio Config (optional) Please check Minio instance for details)
111
+# The attachment host must allow cross origin request - see the description
112
+# above.
112 113
 # S3_ENABLED=true
113 114
 # S3_BUCKET=
114 115
 # AWS_ACCESS_KEY_ID=
@@ -119,12 +120,30 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
119 120
 # S3_ENDPOINT=
120 121
 # S3_SIGNATURE_VERSION=
121 122
 
123
+# Google Cloud Storage (optional)
124
+# Use S3 compatible API. Since GCS does not support Multipart Upload,
125
+# increase the value of S3_MULTIPART_THRESHOLD to disable Multipart Upload.
126
+# The attachment host must allow cross origin request - see the description
127
+# above.
128
+# S3_ENABLED=true
129
+# AWS_ACCESS_KEY_ID=
130
+# AWS_SECRET_ACCESS_KEY=
131
+# S3_REGION=
132
+# S3_PROTOCOL=https
133
+# S3_HOSTNAME=storage.googleapis.com
134
+# S3_ENDPOINT=https://storage.googleapis.com
135
+# S3_MULTIPART_THRESHOLD=52428801 # 50.megabytes
136
+
122 137
 # Swift (optional)
138
+# The attachment host must allow cross origin request - see the description
139
+# above.
123 140
 # SWIFT_ENABLED=true
124 141
 # SWIFT_USERNAME=
125 142
 # For Keystone V3, the value for SWIFT_TENANT should be the project name
126 143
 # SWIFT_TENANT=
127 144
 # SWIFT_PASSWORD=
145
+# Some OpenStack V3 providers require PROJECT_ID (optional)
146
+# SWIFT_PROJECT_ID=
128 147
 # Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
129 148
 # issues with token rate-limiting during high load.
130 149
 # SWIFT_AUTH_URL=
@@ -171,8 +190,8 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
171 190
 # The pam environment variable "email" is provided by:
172 191
 # https://github.com/devkral/pam_email_extractor
173 192
 # PAM_ENABLED=true
174
-# Fallback Suffix for email address generation (nil by default)
175
-# PAM_DEFAULT_SUFFIX=pam
193
+# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
194
+# PAM_EMAIL_DOMAIN=example.com
176 195
 # Name of the pam service (pam "auth" section is evaluated)
177 196
 # PAM_DEFAULT_SERVICE=rpam
178 197
 # Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
@@ -220,7 +239,14 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
220 239
 # SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
221 240
 # SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
222 241
 # SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
223
-# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.5.4.42"
242
+# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241"
243
+# SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42"
244
+# SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4"
224 245
 # SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1"
225 246
 # SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
226 247
 # SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=
248
+
249
+# Use HTTP proxy for outgoing request (optional)
250
+# http_proxy=http://gateway.local:8118
251
+# Access control for hidden service.
252
+# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true

+ 16
- 1
.env.production.sample View File

@@ -69,6 +69,7 @@ SMTP_PORT=587
69 69
 SMTP_LOGIN=
70 70
 SMTP_PASSWORD=
71 71
 SMTP_FROM_ADDRESS=notifications@example.com
72
+#SMTP_REPLY_TO=
72 73
 #SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
73 74
 #SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
74 75
 #SMTP_AUTH_METHOD=plain
@@ -114,6 +115,20 @@ SMTP_FROM_ADDRESS=notifications@example.com
114 115
 # S3_ENDPOINT=
115 116
 # S3_SIGNATURE_VERSION=
116 117
 
118
+# Google Cloud Storage (optional)
119
+# Use S3 compatible API. Since GCS does not support Multipart Upload,
120
+# increase the value of S3_MULTIPART_THRESHOLD to disable Multipart Upload.
121
+# The attachment host must allow cross origin request - see the description
122
+# above.
123
+# S3_ENABLED=true
124
+# AWS_ACCESS_KEY_ID=
125
+# AWS_SECRET_ACCESS_KEY=
126
+# S3_REGION=
127
+# S3_PROTOCOL=https
128
+# S3_HOSTNAME=storage.googleapis.com
129
+# S3_ENDPOINT=https://storage.googleapis.com
130
+# S3_MULTIPART_THRESHOLD=52428801 # 50.megabytes
131
+
117 132
 # Swift (optional)
118 133
 # The attachment host must allow cross origin request - see the description
119 134
 # above.
@@ -163,7 +178,7 @@ STREAMING_CLUSTER_NUM=1
163 178
 # LDAP_BIND_DN=
164 179
 # LDAP_PASSWORD=
165 180
 # LDAP_UID=cn
166
-# LDAP_SEARCH_FILTER="%{uid}=%{email}"
181
+# LDAP_SEARCH_FILTER=%{uid}=%{email}
167 182
 
168 183
 # PAM authentication (optional)
169 184
 # PAM authentication uses for the email generation the "email" pam variable

+ 1
- 1
.ruby-version View File

@@ -1 +1 @@
1
-2.6.1
1
+2.6.5

+ 244
- 426
AUTHORS.md
File diff suppressed because it is too large
View File


+ 229
- 0
CHANGELOG.md View File

@@ -3,6 +3,235 @@ Changelog
3 3
 
4 4
 All notable changes to this project will be documented in this file.
5 5
 
6
+## [3.0.1] - 2019-10-10
7
+### Added
8
+
9
+- Add `tootctl media usage` command ([Gargron](https://github.com/tootsuite/mastodon/pull/12115))
10
+- Add admin setting to auto-approve trending hashtags ([Gargron](https://github.com/tootsuite/mastodon/pull/12122), [Gargron](https://github.com/tootsuite/mastodon/pull/12130))
11
+
12
+### Changed
13
+
14
+- Change `tootctl media refresh` to skip already downloaded attachments ([Gargron](https://github.com/tootsuite/mastodon/pull/12118))
15
+
16
+### Removed
17
+
18
+- Remove auto-silence behaviour from spam check ([Gargron](https://github.com/tootsuite/mastodon/pull/12117))
19
+- Remove HTML `lang` attribute from individual statuses in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12124))
20
+- Remove fallback to long description on sidebar and meta description ([Gargron](https://github.com/tootsuite/mastodon/pull/12119))
21
+
22
+### Fixed
23
+
24
+- Fix preloaded JSON-LD context for identity not being used ([Gargron](https://github.com/tootsuite/mastodon/pull/12138))
25
+- Fix media editing modal changing dimensions once the image loads ([Gargron](https://github.com/tootsuite/mastodon/pull/12131))
26
+- Fix not showing whether a custom emoji has a local counterpart in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12135))
27
+- Fix attachment not being re-downloaded even if file is not stored ([Gargron](https://github.com/tootsuite/mastodon/pull/12125))
28
+- Fix old migration trying to use new column due to default status scope ([Gargron](https://github.com/tootsuite/mastodon/pull/12095))
29
+- Fix column back button missing for not found accounts ([trwnh](https://github.com/tootsuite/mastodon/pull/12094))
30
+- 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))
31
+- Fix existing user records with now-renamed `pt` locale ([Gargron](https://github.com/tootsuite/mastodon/pull/12092))
32
+- Fix hashtag timeline REST API accepting too many hashtags ([Gargron](https://github.com/tootsuite/mastodon/pull/12091))
33
+- Fix `GET /api/v1/instance` REST APIs being unavailable in secure mode ([Gargron](https://github.com/tootsuite/mastodon/pull/12089))
34
+- Fix performance of home feed regeneration and merging ([Gargron](https://github.com/tootsuite/mastodon/pull/12084))
35
+- Fix ffmpeg performance issues due to stdout buffer overflow ([hugogameiro](https://github.com/tootsuite/mastodon/pull/12088))
36
+- Fix S3 adapter retrying failing uploads with exponential backoff ([Gargron](https://github.com/tootsuite/mastodon/pull/12085))
37
+- Fix `tootctl accounts cull` advertising unused option flag ([Kjwon15](https://github.com/tootsuite/mastodon/pull/12074))
38
+
39
+## [3.0.0] - 2019-10-03
40
+### Added
41
+
42
+- Add "not available" label to unloaded media attachments in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11715), [Gargron](https://github.com/tootsuite/mastodon/pull/11745))
43
+- **Add profile directory to web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11688), [mayaeh](https://github.com/tootsuite/mastodon/pull/11872))
44
+  - Add profile directory opt-in federation
45
+  - Add profile directory REST API
46
+- Add special alert for throttled requests in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11677))
47
+- Add confirmation modal when logging out from the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11671))
48
+- **Add audio player in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11644), [Gargron](https://github.com/tootsuite/mastodon/pull/11652), [Gargron](https://github.com/tootsuite/mastodon/pull/11654), [ThibG](https://github.com/tootsuite/mastodon/pull/11629), [Gargron](https://github.com/tootsuite/mastodon/pull/12056))
49
+- **Add autosuggestions for hashtags in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11422), [ThibG](https://github.com/tootsuite/mastodon/pull/11632), [Gargron](https://github.com/tootsuite/mastodon/pull/11764), [Gargron](https://github.com/tootsuite/mastodon/pull/11588), [Gargron](https://github.com/tootsuite/mastodon/pull/11442))
50
+- **Add media editing modal with OCR tool in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11563), [Gargron](https://github.com/tootsuite/mastodon/pull/11566), [ThibG](https://github.com/tootsuite/mastodon/pull/11575), [ThibG](https://github.com/tootsuite/mastodon/pull/11576), [Gargron](https://github.com/tootsuite/mastodon/pull/11577), [Gargron](https://github.com/tootsuite/mastodon/pull/11573), [Gargron](https://github.com/tootsuite/mastodon/pull/11571))
51
+- Add indicator of unread notifications to window title when web UI is out of focus ([Gargron](https://github.com/tootsuite/mastodon/pull/11560), [Gargron](https://github.com/tootsuite/mastodon/pull/11572))
52
+- Add indicator for which options you voted for in a poll in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11195))
53
+- **Add search results pagination to web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11409), [ThibG](https://github.com/tootsuite/mastodon/pull/11447))
54
+- **Add option to disable real-time updates in web UI ("slow mode")** ([Gargron](https://github.com/tootsuite/mastodon/pull/9984), [ykzts](https://github.com/tootsuite/mastodon/pull/11880), [ThibG](https://github.com/tootsuite/mastodon/pull/11883), [Gargron](https://github.com/tootsuite/mastodon/pull/11898), [ThibG](https://github.com/tootsuite/mastodon/pull/11859))
55
+- Add option to disable blurhash previews in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11188))
56
+- Add native smooth scrolling when supported in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11207))
57
+- Add scrolling to the search bar on focus in web UI ([Kjwon15](https://github.com/tootsuite/mastodon/pull/12032))
58
+- Add refresh button to list of rebloggers/favouriters in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12031))
59
+- Add error description and button to copy stack trace to web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12033))
60
+- Add search and sort functions to hashtag admin UI ([mayaeh](https://github.com/tootsuite/mastodon/pull/11829), [Gargron](https://github.com/tootsuite/mastodon/pull/11897), [mayaeh](https://github.com/tootsuite/mastodon/pull/11875))
61
+- Add setting for default search engine indexing in admin UI ([brortao](https://github.com/tootsuite/mastodon/pull/11804))
62
+- Add account bio to account view in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11473))
63
+- **Add option to include reported statuses in warning e-mail from admin UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11639), [Gargron](https://github.com/tootsuite/mastodon/pull/11812), [Gargron](https://github.com/tootsuite/mastodon/pull/11741), [Gargron](https://github.com/tootsuite/mastodon/pull/11698), [mayaeh](https://github.com/tootsuite/mastodon/pull/11765))
64
+- Add number of pending accounts and pending hashtags to dashboard in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11514))
65
+- **Add account migration UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11846), [noellabo](https://github.com/tootsuite/mastodon/pull/11905), [noellabo](https://github.com/tootsuite/mastodon/pull/11907), [noellabo](https://github.com/tootsuite/mastodon/pull/11906), [noellabo](https://github.com/tootsuite/mastodon/pull/11902))
66
+- **Add table of contents to about page** ([Gargron](https://github.com/tootsuite/mastodon/pull/11885), [ykzts](https://github.com/tootsuite/mastodon/pull/11941), [ykzts](https://github.com/tootsuite/mastodon/pull/11895), [Kjwon15](https://github.com/tootsuite/mastodon/pull/11916))
67
+- **Add password challenge to 2FA settings, e-mail notifications** ([Gargron](https://github.com/tootsuite/mastodon/pull/11878))
68
+- **Add optional public list of domain blocks with comments** ([ThibG](https://github.com/tootsuite/mastodon/pull/11298), [ThibG](https://github.com/tootsuite/mastodon/pull/11515), [Gargron](https://github.com/tootsuite/mastodon/pull/11908))
69
+- Add an RSS feed for featured hashtags ([noellabo](https://github.com/tootsuite/mastodon/pull/10502))
70
+- Add explanations to featured hashtags UI and profile ([Gargron](https://github.com/tootsuite/mastodon/pull/11586))
71
+- **Add hashtag trends with admin and user settings** ([Gargron](https://github.com/tootsuite/mastodon/pull/11490), [Gargron](https://github.com/tootsuite/mastodon/pull/11502), [Gargron](https://github.com/tootsuite/mastodon/pull/11641), [Gargron](https://github.com/tootsuite/mastodon/pull/11594), [Gargron](https://github.com/tootsuite/mastodon/pull/11517), [mayaeh](https://github.com/tootsuite/mastodon/pull/11845), [Gargron](https://github.com/tootsuite/mastodon/pull/11774), [Gargron](https://github.com/tootsuite/mastodon/pull/11712), [Gargron](https://github.com/tootsuite/mastodon/pull/11791), [Gargron](https://github.com/tootsuite/mastodon/pull/11743), [Gargron](https://github.com/tootsuite/mastodon/pull/11740), [Gargron](https://github.com/tootsuite/mastodon/pull/11714), [ThibG](https://github.com/tootsuite/mastodon/pull/11631), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/11569), [Gargron](https://github.com/tootsuite/mastodon/pull/11524), [Gargron](https://github.com/tootsuite/mastodon/pull/11513))
72
+  - Add hashtag usage breakdown to admin UI
73
+  - Add batch actions for hashtags to admin UI
74
+  - Add trends to web UI
75
+  - Add trends to public pages
76
+  - Add user preference to hide trends
77
+  - Add admin setting to disable trends
78
+- **Add categories for custom emojis** ([Gargron](https://github.com/tootsuite/mastodon/pull/11196), [Gargron](https://github.com/tootsuite/mastodon/pull/11793), [Gargron](https://github.com/tootsuite/mastodon/pull/11920), [highemerly](https://github.com/tootsuite/mastodon/pull/11876))
79
+  - Add custom emoji categories to emoji picker in web UI
80
+  - Add `category` to custom emojis in REST API
81
+  - Add batch actions for custom emojis in admin UI
82
+- Add max image dimensions to error message ([raboof](https://github.com/tootsuite/mastodon/pull/11552))
83
+- Add aac, m4a, 3gp, amr, wma to allowed audio formats ([Gargron](https://github.com/tootsuite/mastodon/pull/11342), [umonaca](https://github.com/tootsuite/mastodon/pull/11687))
84
+- **Add search syntax for operators and phrases** ([Gargron](https://github.com/tootsuite/mastodon/pull/11411))
85
+- **Add REST API for managing featured hashtags** ([noellabo](https://github.com/tootsuite/mastodon/pull/11778))
86
+- **Add REST API for managing timeline read markers** ([Gargron](https://github.com/tootsuite/mastodon/pull/11762))
87
+- Add `exclude_unreviewed` param to `GET /api/v2/search` REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/11977))
88
+- Add `reason` param to `POST /api/v1/accounts` REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/12064))
89
+- **Add ActivityPub secure mode** ([Gargron](https://github.com/tootsuite/mastodon/pull/11269), [ThibG](https://github.com/tootsuite/mastodon/pull/11332), [ThibG](https://github.com/tootsuite/mastodon/pull/11295))
90
+- Add HTTP signatures to all outgoing ActivityPub GET requests ([Gargron](https://github.com/tootsuite/mastodon/pull/11284), [ThibG](https://github.com/tootsuite/mastodon/pull/11300))
91
+- Add support for ActivityPub Audio activities ([ThibG](https://github.com/tootsuite/mastodon/pull/11189))
92
+- Add ActivityPub actor representing the entire server ([ThibG](https://github.com/tootsuite/mastodon/pull/11321), [rtucker](https://github.com/tootsuite/mastodon/pull/11400), [ThibG](https://github.com/tootsuite/mastodon/pull/11561), [Gargron](https://github.com/tootsuite/mastodon/pull/11798))
93
+- **Add whitelist mode** ([Gargron](https://github.com/tootsuite/mastodon/pull/11291), [mayaeh](https://github.com/tootsuite/mastodon/pull/11634))
94
+- Add config of multipart threshold for S3 ([ykzts](https://github.com/tootsuite/mastodon/pull/11924), [ykzts](https://github.com/tootsuite/mastodon/pull/11944))
95
+- Add health check endpoint for web ([ykzts](https://github.com/tootsuite/mastodon/pull/11770), [ykzts](https://github.com/tootsuite/mastodon/pull/11947))
96
+- Add HTTP signature keyId to request log ([Gargron](https://github.com/tootsuite/mastodon/pull/11591))
97
+- Add `SMTP_REPLY_TO` environment variable ([hugogameiro](https://github.com/tootsuite/mastodon/pull/11718))
98
+- Add `tootctl preview_cards remove` command ([mayaeh](https://github.com/tootsuite/mastodon/pull/11320))
99
+- Add `tootctl media refresh` command ([Gargron](https://github.com/tootsuite/mastodon/pull/11775))
100
+- Add `tootctl cache recount` command ([Gargron](https://github.com/tootsuite/mastodon/pull/11597))
101
+- Add option to exclude suspended domains from `tootctl domains crawl` ([dariusk](https://github.com/tootsuite/mastodon/pull/11454))
102
+- Add parallelization to `tootctl search deploy` ([noellabo](https://github.com/tootsuite/mastodon/pull/12051))
103
+- Add soft delete for statuses for instant deletes through API ([Gargron](https://github.com/tootsuite/mastodon/pull/11623), [Gargron](https://github.com/tootsuite/mastodon/pull/11648))
104
+- Add rails-level JSON caching ([Gargron](https://github.com/tootsuite/mastodon/pull/11333), [Gargron](https://github.com/tootsuite/mastodon/pull/11271))
105
+- **Add request pool to improve delivery performance** ([Gargron](https://github.com/tootsuite/mastodon/pull/10353), [ykzts](https://github.com/tootsuite/mastodon/pull/11756))
106
+- Add concurrent connection attempts to resolved IP addresses ([ThibG](https://github.com/tootsuite/mastodon/pull/11757))
107
+- Add index for remember_token to improve login performance ([abcang](https://github.com/tootsuite/mastodon/pull/11881))
108
+- **Add more accurate hashtag search** ([Gargron](https://github.com/tootsuite/mastodon/pull/11579), [Gargron](https://github.com/tootsuite/mastodon/pull/11427), [Gargron](https://github.com/tootsuite/mastodon/pull/11448))
109
+- **Add more accurate account search** ([Gargron](https://github.com/tootsuite/mastodon/pull/11537), [Gargron](https://github.com/tootsuite/mastodon/pull/11580))
110
+- **Add a spam check** ([Gargron](https://github.com/tootsuite/mastodon/pull/11217), [Gargron](https://github.com/tootsuite/mastodon/pull/11806), [ThibG](https://github.com/tootsuite/mastodon/pull/11296))
111
+- Add new languages ([Gargron](https://github.com/tootsuite/mastodon/pull/12062))
112
+  - Breton
113
+  - Spanish (Argentina)
114
+  - Estonian
115
+  - Macedonian
116
+  - New Norwegian
117
+- Add NodeInfo endpoint ([Gargron](https://github.com/tootsuite/mastodon/pull/12002), [Gargron](https://github.com/tootsuite/mastodon/pull/12058))
118
+
119
+### Changed
120
+
121
+- **Change conversations UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11896))
122
+- Change dashboard to short number notation ([noellabo](https://github.com/tootsuite/mastodon/pull/11847), [noellabo](https://github.com/tootsuite/mastodon/pull/11911))
123
+- Change REST API `GET /api/v1/timelines/public` to require authentication when public preview is off ([ThibG](https://github.com/tootsuite/mastodon/pull/11802))
124
+- Change REST API `POST /api/v1/follow_requests/:id/(approve|reject)` to return relationship ([ThibG](https://github.com/tootsuite/mastodon/pull/11800))
125
+- Change rate limit for media proxy ([ykzts](https://github.com/tootsuite/mastodon/pull/11814))
126
+- Change unlisted custom emoji to not appear in autosuggestions ([Gargron](https://github.com/tootsuite/mastodon/pull/11818))
127
+- Change max length of media descriptions from 420 to 1500 characters ([Gargron](https://github.com/tootsuite/mastodon/pull/11819), [ThibG](https://github.com/tootsuite/mastodon/pull/11836))
128
+- **Change deletes to preserve soft-deleted statuses in unresolved reports** ([Gargron](https://github.com/tootsuite/mastodon/pull/11805))
129
+- **Change tootctl to use inline parallelization instead of Sidekiq** ([Gargron](https://github.com/tootsuite/mastodon/pull/11776))
130
+- **Change account deletion page to have better explanations** ([Gargron](https://github.com/tootsuite/mastodon/pull/11753), [Gargron](https://github.com/tootsuite/mastodon/pull/11763))
131
+- Change hashtag component in web UI to show numbers for 2 last days ([Gargron](https://github.com/tootsuite/mastodon/pull/11742), [Gargron](https://github.com/tootsuite/mastodon/pull/11755), [Gargron](https://github.com/tootsuite/mastodon/pull/11754))
132
+- Change OpenGraph description on sign-up page to reflect invite ([Gargron](https://github.com/tootsuite/mastodon/pull/11744))
133
+- Change layout of public profile directory to be the same as in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11705))
134
+- Change detailed status child ordering to sort self-replies on top ([ThibG](https://github.com/tootsuite/mastodon/pull/11686))
135
+- Change window resize handler to switch to/from mobile layout as soon as needed ([ThibG](https://github.com/tootsuite/mastodon/pull/11656))
136
+- Change icon button styles to make hover/focus states more obvious ([ThibG](https://github.com/tootsuite/mastodon/pull/11474))
137
+- Change contrast of status links that are not mentions or hashtags ([ThibG](https://github.com/tootsuite/mastodon/pull/11406))
138
+- **Change hashtags to preserve first-used casing** ([Gargron](https://github.com/tootsuite/mastodon/pull/11416), [Gargron](https://github.com/tootsuite/mastodon/pull/11508), [Gargron](https://github.com/tootsuite/mastodon/pull/11504), [Gargron](https://github.com/tootsuite/mastodon/pull/11507), [Gargron](https://github.com/tootsuite/mastodon/pull/11441))
139
+- **Change unconfirmed user login behaviour** ([Gargron](https://github.com/tootsuite/mastodon/pull/11375), [ThibG](https://github.com/tootsuite/mastodon/pull/11394), [Gargron](https://github.com/tootsuite/mastodon/pull/11860))
140
+- **Change single-column mode to scroll the whole page** ([Gargron](https://github.com/tootsuite/mastodon/pull/11359), [Gargron](https://github.com/tootsuite/mastodon/pull/11894), [Gargron](https://github.com/tootsuite/mastodon/pull/11891), [ThibG](https://github.com/tootsuite/mastodon/pull/11655), [Gargron](https://github.com/tootsuite/mastodon/pull/11463), [Gargron](https://github.com/tootsuite/mastodon/pull/11458), [ThibG](https://github.com/tootsuite/mastodon/pull/11395), [Gargron](https://github.com/tootsuite/mastodon/pull/11418))
141
+- Change `tootctl accounts follow` to only work with local accounts ([angristan](https://github.com/tootsuite/mastodon/pull/11592))
142
+- Change Dockerfile ([Shleeble](https://github.com/tootsuite/mastodon/pull/11710), [ykzts](https://github.com/tootsuite/mastodon/pull/11768), [Shleeble](https://github.com/tootsuite/mastodon/pull/11707))
143
+- Change supported Node versions to include v12 ([abcang](https://github.com/tootsuite/mastodon/pull/11706))
144
+- Change Portuguese language from `pt` to `pt-PT` ([Gargron](https://github.com/tootsuite/mastodon/pull/11820))
145
+- Change domain block silence to always require approval on follow ([ThibG](https://github.com/tootsuite/mastodon/pull/11975))
146
+- Change link preview fetcher to not perform a HEAD request first ([Gargron](https://github.com/tootsuite/mastodon/pull/12028))
147
+- Change `tootctl domains purge` to accept multiple domains at once ([Gargron](https://github.com/tootsuite/mastodon/pull/12046))
148
+
149
+### Removed
150
+
151
+- **Remove OStatus support** ([Gargron](https://github.com/tootsuite/mastodon/pull/11205), [Gargron](https://github.com/tootsuite/mastodon/pull/11303), [Gargron](https://github.com/tootsuite/mastodon/pull/11460), [ThibG](https://github.com/tootsuite/mastodon/pull/11280), [ThibG](https://github.com/tootsuite/mastodon/pull/11278))
152
+- Remove Atom feeds and old URLs in the form of `GET /:username/updates/:id` ([Gargron](https://github.com/tootsuite/mastodon/pull/11247))
153
+- Remove WebP support ([angristan](https://github.com/tootsuite/mastodon/pull/11589))
154
+- Remove deprecated config options from Heroku and Scalingo ([ykzts](https://github.com/tootsuite/mastodon/pull/11925))
155
+- Remove deprecated REST API `GET /api/v1/search` API ([Gargron](https://github.com/tootsuite/mastodon/pull/11823))
156
+- Remove deprecated REST API `GET /api/v1/statuses/:id/card` ([Gargron](https://github.com/tootsuite/mastodon/pull/11213))
157
+- Remove deprecated REST API `POST /api/v1/notifications/dismiss?id=:id` ([Gargron](https://github.com/tootsuite/mastodon/pull/11214))
158
+- Remove deprecated REST API `GET /api/v1/timelines/direct` ([Gargron](https://github.com/tootsuite/mastodon/pull/11212))
159
+
160
+### Fixed
161
+
162
+- Fix manifest warning ([ykzts](https://github.com/tootsuite/mastodon/pull/11767))
163
+- Fix admin UI for custom emoji not respecting GIF autoplay preference ([ThibG](https://github.com/tootsuite/mastodon/pull/11801))
164
+- Fix page body not being scrollable in admin/settings layout ([Gargron](https://github.com/tootsuite/mastodon/pull/11893))
165
+- Fix placeholder colors for inputs not being explicitly defined ([Gargron](https://github.com/tootsuite/mastodon/pull/11890))
166
+- Fix incorrect enclosure length in RSS ([tsia](https://github.com/tootsuite/mastodon/pull/11889))
167
+- Fix TOTP codes not being filtered from logs during enabling/disabling ([Gargron](https://github.com/tootsuite/mastodon/pull/11877))
168
+- Fix webfinger response not returning 410 when account is suspended ([Gargron](https://github.com/tootsuite/mastodon/pull/11869))
169
+- Fix ActivityPub Move handler queuing jobs that will fail if account is suspended ([Gargron](https://github.com/tootsuite/mastodon/pull/11864))
170
+- Fix SSO login not using existing account when e-mail is verified ([Gargron](https://github.com/tootsuite/mastodon/pull/11862))
171
+- Fix web UI allowing uploads past status limit via drag & drop ([Gargron](https://github.com/tootsuite/mastodon/pull/11863))
172
+- Fix expiring polls not being displayed as such in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11835))
173
+- Fix 2FA challenge and password challenge for non-database users ([Gargron](https://github.com/tootsuite/mastodon/pull/11831), [Gargron](https://github.com/tootsuite/mastodon/pull/11943))
174
+- Fix profile fields overflowing page width in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11828))
175
+- Fix web push subscriptions being deleted on rate limit or timeout ([Gargron](https://github.com/tootsuite/mastodon/pull/11826))
176
+- Fix display of long poll options in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11717), [ThibG](https://github.com/tootsuite/mastodon/pull/11833))
177
+- Fix search API not resolving URL when `type` is given ([Gargron](https://github.com/tootsuite/mastodon/pull/11822))
178
+- Fix hashtags being split by ZWNJ character ([Gargron](https://github.com/tootsuite/mastodon/pull/11821))
179
+- Fix scroll position resetting when opening media modals in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11815))
180
+- Fix duplicate HTML IDs on about page ([ThibG](https://github.com/tootsuite/mastodon/pull/11803))
181
+- Fix admin UI showing superfluous reject media/reports on suspended domain blocks ([ThibG](https://github.com/tootsuite/mastodon/pull/11749))
182
+- Fix ActivityPub context not being dynamically computed ([ThibG](https://github.com/tootsuite/mastodon/pull/11746))
183
+- Fix Mastodon logo style on hover on public pages' footer ([ThibG](https://github.com/tootsuite/mastodon/pull/11735))
184
+- Fix height of dashboard counters ([ThibG](https://github.com/tootsuite/mastodon/pull/11736))
185
+- Fix custom emoji animation on hover in web UI directory bios ([ThibG](https://github.com/tootsuite/mastodon/pull/11716))
186
+- Fix non-numbers being passed to Redis and causing an error ([Gargron](https://github.com/tootsuite/mastodon/pull/11697))
187
+- Fix error in REST API for an account's statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/11700))
188
+- Fix uncaught error when resource param is missing in Webfinger request ([Gargron](https://github.com/tootsuite/mastodon/pull/11701))
189
+- Fix uncaught domain normalization error in remote follow ([Gargron](https://github.com/tootsuite/mastodon/pull/11703))
190
+- Fix uncaught 422 and 500 errors ([Gargron](https://github.com/tootsuite/mastodon/pull/11590), [Gargron](https://github.com/tootsuite/mastodon/pull/11811))
191
+- Fix uncaught parameter missing exceptions and missing error templates ([Gargron](https://github.com/tootsuite/mastodon/pull/11702))
192
+- Fix encoding error when checking e-mail MX records ([Gargron](https://github.com/tootsuite/mastodon/pull/11696))
193
+- Fix items in StatusContent render list not all having a key ([ThibG](https://github.com/tootsuite/mastodon/pull/11645))
194
+- Fix remote and staff-removed statuses leaving media behind for a day ([Gargron](https://github.com/tootsuite/mastodon/pull/11638))
195
+- Fix CSP needlessly allowing blob URLs in script-src ([ThibG](https://github.com/tootsuite/mastodon/pull/11620))
196
+- Fix ignoring whole status because of one invalid hashtag ([Gargron](https://github.com/tootsuite/mastodon/pull/11621))
197
+- Fix hidden statuses losing focus ([ThibG](https://github.com/tootsuite/mastodon/pull/11208))
198
+- Fix loading bar being obscured by other elements in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11598))
199
+- Fix multiple issues with replies collection for pages further than self-replies ([ThibG](https://github.com/tootsuite/mastodon/pull/11582))
200
+- Fix blurhash and autoplay not working on public pages ([Gargron](https://github.com/tootsuite/mastodon/pull/11585))
201
+- Fix 422 being returned instead of 404 when POSTing to unmatched routes ([Gargron](https://github.com/tootsuite/mastodon/pull/11574), [Gargron](https://github.com/tootsuite/mastodon/pull/11704))
202
+- Fix client-side resizing of image uploads ([ThibG](https://github.com/tootsuite/mastodon/pull/11570))
203
+- Fix short number formatting for numbers above million in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11559))
204
+- Fix ActivityPub and REST API queries setting cookies and preventing caching ([ThibG](https://github.com/tootsuite/mastodon/pull/11539), [ThibG](https://github.com/tootsuite/mastodon/pull/11557), [ThibG](https://github.com/tootsuite/mastodon/pull/11336), [ThibG](https://github.com/tootsuite/mastodon/pull/11331))
205
+- Fix some emojis in profile metadata labels are not emojified. ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/11534))
206
+- Fix account search always returning exact match on paginated results ([Gargron](https://github.com/tootsuite/mastodon/pull/11525))
207
+- Fix acct URIs with IDN domains not being resolved ([Gargron](https://github.com/tootsuite/mastodon/pull/11520))
208
+- Fix admin dashboard missing latest features ([Gargron](https://github.com/tootsuite/mastodon/pull/11505))
209
+- Fix jumping of toot date when clicking spoiler button ([ariasuni](https://github.com/tootsuite/mastodon/pull/11449))
210
+- Fix boost to original audience not working on mobile in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11371))
211
+- Fix handling of webfinger redirects in ResolveAccountService ([ThibG](https://github.com/tootsuite/mastodon/pull/11279))
212
+- Fix URLs appearing twice in errors of ActivityPub::DeliveryWorker ([Gargron](https://github.com/tootsuite/mastodon/pull/11231))
213
+- Fix support for HTTP proxies ([ThibG](https://github.com/tootsuite/mastodon/pull/11245))
214
+- Fix HTTP requests to IPv6 hosts ([ThibG](https://github.com/tootsuite/mastodon/pull/11240))
215
+- Fix error in ElasticSearch index import ([mayaeh](https://github.com/tootsuite/mastodon/pull/11192))
216
+- Fix duplicate account error when seeding development database ([ysksn](https://github.com/tootsuite/mastodon/pull/11366))
217
+- Fix performance of session clean-up scheduler ([abcang](https://github.com/tootsuite/mastodon/pull/11871))
218
+- Fix older migrations not running ([zunda](https://github.com/tootsuite/mastodon/pull/11377))
219
+- Fix URLs counting towards RTL detection ([ahangarha](https://github.com/tootsuite/mastodon/pull/11759))
220
+- Fix unnecessary status re-rendering in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11211))
221
+- Fix http_parser.rb gem not being compiled when no network available ([petabyteboy](https://github.com/tootsuite/mastodon/pull/11444))
222
+- Fix muted text color not applying to all text ([trwnh](https://github.com/tootsuite/mastodon/pull/11996))
223
+- Fix follower/following lists resetting on back-navigation in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11986))
224
+- Fix n+1 query when approving multiple follow requests ([abcang](https://github.com/tootsuite/mastodon/pull/12004))
225
+- Fix records not being indexed into ElasticSearch sometimes ([Gargron](https://github.com/tootsuite/mastodon/pull/12024))
226
+- Fix needlessly indexing unsearchable statuses into ElasticSearch ([Gargron](https://github.com/tootsuite/mastodon/pull/12041))
227
+- Fix new user bootstrapping crashing when to-be-followed accounts are invalid ([ThibG](https://github.com/tootsuite/mastodon/pull/12037))
228
+- Fix featured hashtag URL being interpreted as media or replies tab ([Gargron](https://github.com/tootsuite/mastodon/pull/12048))
229
+- Fix account counters being overwritten by parallel writes ([Gargron](https://github.com/tootsuite/mastodon/pull/12045))
230
+
231
+### Security
232
+
233
+- Fix performance of GIF re-encoding and always strip EXIF data from videos ([Gargron](https://github.com/tootsuite/mastodon/pull/12057))
234
+
6 235
 ## [2.9.3] - 2019-08-10
7 236
 ### Added
8 237
 

+ 9
- 11
Dockerfile View File

@@ -4,22 +4,20 @@ FROM ubuntu:18.04 as build-dep
4 4
 SHELL ["bash", "-c"]
5 5
 
6 6
 # Install Node
7
-ENV NODE_VER="8.15.0"
7
+ENV NODE_VER="12.11.1"
8 8
 RUN	echo "Etc/UTC" > /etc/localtime && \
9 9
 	apt update && \
10
-	apt -y install wget make gcc g++ python && \
10
+	apt -y install wget python && \
11 11
 	cd ~ && \
12
-	wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER.tar.gz && \
13
-	tar xf node-v$NODE_VER.tar.gz && \
14
-	cd node-v$NODE_VER && \
15
-	./configure --prefix=/opt/node && \
16
-	make -j$(nproc) > /dev/null && \
17
-	make install
12
+	wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER-linux-x64.tar.gz && \
13
+	tar xf node-v$NODE_VER-linux-x64.tar.gz && \
14
+	rm node-v$NODE_VER-linux-x64.tar.gz && \
15
+	mv node-v$NODE_VER-linux-x64 /opt/node
18 16
 
19 17
 # Install jemalloc
20
-ENV JE_VER="5.1.0"
18
+ENV JE_VER="5.2.1"
21 19
 RUN apt update && \
22
-	apt -y install autoconf && \
20
+	apt -y install make autoconf gcc g++ && \
23 21
 	cd ~ && \
24 22
 	wget https://github.com/jemalloc/jemalloc/archive/$JE_VER.tar.gz && \
25 23
 	tar xf $JE_VER.tar.gz && \
@@ -30,7 +28,7 @@ RUN apt update && \
30 28
 	make install_bin install_include install_lib
31 29
 
32 30
 # Install ruby
33
-ENV RUBY_VER="2.6.1"
31
+ENV RUBY_VER="2.6.5"
34 32
 ENV CPPFLAGS="-I/opt/jemalloc/include"
35 33
 ENV LDFLAGS="-L/opt/jemalloc/lib/"
36 34
 RUN apt update && \

+ 31
- 24
Gemfile View File

@@ -5,17 +5,17 @@ ruby '>= 2.4.0', '< 2.7.0'
5 5
 
6 6
 gem 'pkg-config', '~> 1.3'
7 7
 
8
-gem 'puma', '~> 3.12'
8
+gem 'puma', '~> 4.2'
9 9
 gem 'rails', '~> 5.2.3'
10 10
 gem 'thor', '~> 0.20'
11 11
 
12 12
 gem 'hamlit-rails', '~> 0.2'
13 13
 gem 'pg', '~> 1.1'
14 14
 gem 'makara', '~> 0.4'
15
-gem 'pghero', '~> 2.2'
15
+gem 'pghero', '~> 2.3'
16 16
 gem 'dotenv-rails', '~> 2.7'
17 17
 
18
-gem 'aws-sdk-s3', '~> 1.42', require: false
18
+gem 'aws-sdk-s3', '~> 1.48', require: false
19 19
 gem 'fog-core', '<= 2.1.0'
20 20
 gem 'fog-openstack', '~> 0.3', require: false
21 21
 gem 'paperclip', '~> 6.0'
@@ -24,15 +24,15 @@ gem 'streamio-ffmpeg', '~> 3.0'
24 24
 gem 'blurhash', '~> 0.1'
25 25
 
26 26
 gem 'active_model_serializers', '~> 0.10'
27
-gem 'addressable', '~> 2.6'
27
+gem 'addressable', '~> 2.7'
28 28
 gem 'bootsnap', '~> 1.4', require: false
29 29
 gem 'browser'
30 30
 gem 'charlock_holmes', '~> 0.7.6'
31 31
 gem 'iso-639'
32
-gem 'chewy', '~> 5.0'
32
+gem 'chewy', '~> 5.1'
33 33
 gem 'cld3', '~> 3.2.4'
34
-gem 'devise', '~> 4.6'
35
-gem 'devise-two-factor', '~> 3.0'
34
+gem 'devise', '~> 4.7'
35
+gem 'devise-two-factor', '~> 3.1'
36 36
 
37 37
 group :pam_authentication, optional: true do
38 38
   gem 'devise_pam_authenticatable2', '~> 9.2'
@@ -43,54 +43,60 @@ gem 'omniauth-cas', '~> 1.1'
43 43
 gem 'omniauth-saml', '~> 1.10'
44 44
 gem 'omniauth', '~> 1.9'
45 45
 
46
-gem 'doorkeeper', '~> 5.1'
46
+gem 'discard', '~> 1.1'
47
+gem 'doorkeeper', '~> 5.2'
47 48
 gem 'fast_blank', '~> 1.0'
48 49
 gem 'fastimage'
49 50
 gem 'goldfinger', '~> 2.1'
50 51
 gem 'hiredis', '~> 0.6'
51 52
 gem 'redis-namespace', '~> 1.5'
53
+gem 'health_check', git: 'https://github.com/ianheggie/health_check', ref: '0b799ead604f900ed50685e9b2d469cd2befba5b'
52 54
 gem 'htmlentities', '~> 4.3'
53 55
 gem 'http', '~> 3.3'
54 56
 gem 'http_accept_language', '~> 2.1'
55
-gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2'
57
+gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2', submodules: true
56 58
 gem 'httplog', '~> 1.3'
57 59
 gem 'idn-ruby', require: 'idn'
58 60
 gem 'kaminari', '~> 1.1'
59 61
 gem 'link_header', '~> 0.0'
60
-gem 'mime-types', '~> 3.2', require: 'mime/types/columnar'
62
+gem 'mime-types', '~> 3.3', require: 'mime/types/columnar'
63
+gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532'
61 64
 gem 'nokogiri', '~> 1.10'
62 65
 gem 'nsa', '~> 0.2'
63
-gem 'oj', '~> 3.7'
66
+gem 'oj', '~> 3.9'
64 67
 gem 'ostatus2', '~> 2.0'
65 68
 gem 'ox', '~> 2.11'
69
+gem 'parslet'
70
+gem 'parallel', '~> 1.17'
66 71
 gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
67
-gem 'pundit', '~> 2.0'
72
+gem 'pundit', '~> 2.1'
68 73
 gem 'premailer-rails'
69
-gem 'rack-attack', '~> 6.0'
74
+gem 'rack-attack', '~> 6.1'
70 75
 gem 'rack-cors', '~> 1.0', require: 'rack/cors'
71 76
 gem 'rails-i18n', '~> 5.1'
72 77
 gem 'rails-settings-cached', '~> 0.6'
73 78
 gem 'redis', '~> 4.1', require: ['redis', 'redis/connection/hiredis']
74 79
 gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
75 80
 gem 'rqrcode', '~> 0.10'
76
-gem 'sanitize', '~> 5.0'
81
+gem 'ruby-progressbar', '~> 1.10'
82
+gem 'sanitize', '~> 5.1'
77 83
 gem 'sidekiq', '~> 5.2'
78 84
 gem 'sidekiq-scheduler', '~> 3.0'
79 85
 gem 'sidekiq-unique-jobs', '~> 6.0'
80 86
 gem 'sidekiq-bulk', '~>0.2.0'
81
-gem 'simple-navigation', '~> 4.0'
87
+gem 'simple-navigation', '~> 4.1'
82 88
 gem 'simple_form', '~> 4.1'
83 89
 gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
84 90
 gem 'stoplight', '~> 2.1.3'
85 91
 gem 'strong_migrations', '~> 0.4'
86
-gem 'tty-command', '~> 0.8', require: false
92
+gem 'tty-command', '~> 0.9', require: false
87 93
 gem 'tty-prompt', '~> 0.19', require: false
88 94
 gem 'twitter-text', '~> 1.14'
89 95
 gem 'tzinfo-data', '~> 1.2019'
90 96
 gem 'webpacker', '~> 4.0'
91 97
 gem 'webpush'
92 98
 
93
-gem 'json-ld', '~> 3.0'
99
+gem 'json-ld', git: 'https://github.com/ruby-rdf/json-ld.git', ref: 'e742697a0906e74e8bb777ef98137bc3955d981d'
94 100
 gem 'json-ld-preloaded', '~> 3.0'
95 101
 gem 'rdf-normalize', '~> 0.3'
96 102
 
@@ -108,14 +114,14 @@ group :production, :test do
108 114
 end
109 115
 
110 116
 group :test do
111
-  gem 'capybara', '~> 3.24'
117
+  gem 'capybara', '~> 3.29'
112 118
   gem 'climate_control', '~> 0.2'
113
-  gem 'faker', '~> 1.9'
119
+  gem 'faker', '~> 2.5'
114 120
   gem 'microformats', '~> 4.1'
115 121
   gem 'rails-controller-testing', '~> 1.0'
116 122
   gem 'rspec-sidekiq', '~> 3.0'
117
-  gem 'simplecov', '~> 0.16', require: false
118
-  gem 'webmock', '~> 3.6'
123
+  gem 'simplecov', '~> 0.17', require: false
124
+  gem 'webmock', '~> 3.7'
119 125
   gem 'parallel_tests', '~> 2.29'
120 126
 end
121 127
 
@@ -128,9 +134,9 @@ group :development do
128 134
   gem 'letter_opener', '~> 1.7'
129 135
   gem 'letter_opener_web', '~> 1.3'
130 136
   gem 'memory_profiler'
131
-  gem 'rubocop', '~> 0.71', require: false
132
-  gem 'rubocop-rails', '~> 2.0', require: false
133
-  gem 'brakeman', '~> 4.5', require: false
137
+  gem 'rubocop', '~> 0.74', require: false
138
+  gem 'rubocop-rails', '~> 2.3', require: false
139
+  gem 'brakeman', '~> 4.6', require: false
134 140
   gem 'bundler-audit', '~> 0.6', require: false
135 141
 
136 142
   gem 'capistrano', '~> 3.11'
@@ -148,3 +154,4 @@ group :production do
148 154
 end
149 155
 
150 156
 gem 'concurrent-ruby', require: false
157
+gem 'connection_pool', require: false

+ 165
- 124
Gemfile.lock View File

@@ -1,3 +1,11 @@
1
+GIT
2
+  remote: https://github.com/ianheggie/health_check
3
+  revision: 0b799ead604f900ed50685e9b2d469cd2befba5b
4
+  ref: 0b799ead604f900ed50685e9b2d469cd2befba5b
5
+  specs:
6
+    health_check (4.0.0.pre)
7
+      rails (>= 4.0)
8
+
1 9
 GIT
2 10
   remote: https://github.com/rtomayko/posix-spawn
3 11
   revision: 58465d2e213991f8afb13b984854a49fcdcc980c
@@ -5,13 +13,34 @@ GIT
5 13
   specs:
6 14
     posix-spawn (0.3.13)
7 15
 
16
+GIT
17
+  remote: https://github.com/ruby-rdf/json-ld.git
18
+  revision: e742697a0906e74e8bb777ef98137bc3955d981d
19
+  ref: e742697a0906e74e8bb777ef98137bc3955d981d
20
+  specs:
21
+    json-ld (3.0.2)
22
+      htmlentities (~> 4.3)
23
+      json-canonicalization (~> 0.1)
24
+      link_header (~> 0.0, >= 0.0.8)
25
+      multi_json (~> 1.13)
26
+      rack (>= 1.6, < 3.0)
27
+      rdf (~> 3.0, >= 3.0.8)
28
+
8 29
 GIT
9 30
   remote: https://github.com/tmm1/http_parser.rb
10 31
   revision: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
11 32
   ref: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
33
+  submodules: true
12 34
   specs:
13 35
     http_parser.rb (0.6.1)
14 36
 
37
+GIT
38
+  remote: https://github.com/witgo/nilsimsa
39
+  revision: fd184883048b922b176939f851338d0a4971a532
40
+  ref: fd184883048b922b176939f851338d0a4971a532
41
+  specs:
42
+    nilsimsa (1.1.2)
43
+
15 44
 GEM
16 45
   remote: https://rubygems.org/
17 46
   specs:
@@ -38,9 +67,9 @@ GEM
38 67
       erubi (~> 1.4)
39 68
       rails-dom-testing (~> 2.0)
40 69
       rails-html-sanitizer (~> 1.0, >= 1.0.3)
41
-    active_model_serializers (0.10.9)
42
-      actionpack (>= 4.1, < 6)
43
-      activemodel (>= 4.1, < 6)
70
+    active_model_serializers (0.10.10)
71
+      actionpack (>= 4.1, < 6.1)
72
+      activemodel (>= 4.1, < 6.1)
44 73
       case_transform (>= 0.2)
45 74
       jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
46 75
     active_record_query_trace (1.6.2)
@@ -62,9 +91,9 @@ GEM
62 91
       i18n (>= 0.7, < 2)
63 92
       minitest (~> 5.1)
64 93
       tzinfo (~> 1.1)
65
-    addressable (2.6.0)
66
-      public_suffix (>= 2.0.2, < 4.0)
67
-    airbrussh (1.3.0)
94
+    addressable (2.7.0)
95
+      public_suffix (>= 2.0.2, < 5.0)
96
+    airbrussh (1.3.4)
68 97
       sshkit (>= 1.6.1, != 1.7.0)
69 98
     annotate (2.7.5)
70 99
       activerecord (>= 3.2, < 7.0)
@@ -76,17 +105,17 @@ GEM
76 105
     av (0.9.0)
77 106
       cocaine (~> 0.5.3)
78 107
     aws-eventstream (1.0.3)
79
-    aws-partitions (1.175.0)
80
-    aws-sdk-core (3.55.0)
108
+    aws-partitions (1.207.0)
109
+    aws-sdk-core (3.65.1)
81 110
       aws-eventstream (~> 1.0, >= 1.0.2)
82 111
       aws-partitions (~> 1.0)
83 112
       aws-sigv4 (~> 1.1)
84 113
       jmespath (~> 1.0)
85
-    aws-sdk-kms (1.21.0)
86
-      aws-sdk-core (~> 3, >= 3.53.0)
114
+    aws-sdk-kms (1.24.0)
115
+      aws-sdk-core (~> 3, >= 3.61.1)
87 116
       aws-sigv4 (~> 1.1)
88
-    aws-sdk-s3 (1.42.0)
89
-      aws-sdk-core (~> 3, >= 3.53.0)
117
+    aws-sdk-s3 (1.48.0)
118
+      aws-sdk-core (~> 3, >= 3.61.1)
90 119
       aws-sdk-kms (~> 1)
91 120
       aws-sigv4 (~> 1.1)
92 121
     aws-sigv4 (1.1.0)
@@ -101,19 +130,19 @@ GEM
101 130
       debug_inspector (>= 0.0.1)
102 131
     blurhash (0.1.3)
103 132
       ffi (~> 1.10.0)
104
-    bootsnap (1.4.4)
133
+    bootsnap (1.4.5)
105 134
       msgpack (~> 1.0)
106
-    brakeman (4.5.1)
107
-    browser (2.5.3)
135
+    brakeman (4.6.1)
136
+    browser (2.6.1)
108 137
     builder (3.2.3)
109
-    bullet (6.0.0)
138
+    bullet (6.0.2)
110 139
       activesupport (>= 3.0.0)
111 140
       uniform_notifier (~> 1.11)
112 141
     bundler-audit (0.6.1)
113 142
       bundler (>= 1.2.0, < 3)
114 143
       thor (~> 0.18)
115 144
     byebug (11.0.0)
116
-    capistrano (3.11.0)
145
+    capistrano (3.11.2)
117 146
       airbrussh (>= 1.0.0)
118 147
       i18n
119 148
       rake (>= 10.0.0)
@@ -129,7 +158,7 @@ GEM
129 158
       sshkit (~> 1.3)
130 159
     capistrano-yarn (2.0.2)
131 160
       capistrano (~> 3.0)
132
-    capybara (3.24.0)
161
+    capybara (3.29.0)
133 162
       addressable
134 163
       mini_mime (>= 0.1.3)
135 164
       nokogiri (~> 1.8)
@@ -140,7 +169,7 @@ GEM
140 169
     case_transform (0.2)
141 170
       activesupport
142 171
     charlock_holmes (0.7.6)
143
-    chewy (5.0.0)
172
+    chewy (5.1.0)
144 173
       activesupport (>= 4.0)
145 174
       elasticsearch (>= 2.0.0)
146 175
       elasticsearch-dsl
@@ -156,64 +185,67 @@ GEM
156 185
     crack (0.4.3)
157 186
       safe_yaml (~> 1.0.0)
158 187
     crass (1.0.4)
159
-    css_parser (1.6.0)
188
+    css_parser (1.7.0)
160 189
       addressable
161 190
     debug_inspector (0.0.3)
162
-    derailed_benchmarks (1.3.5)
191
+    derailed_benchmarks (1.4.0)
163 192
       benchmark-ips (~> 2)
164 193
       get_process_mem (~> 0)
165 194
       heapy (~> 0)
166 195
       memory_profiler (~> 0)
167 196
       rack (>= 1)
168 197
       rake (> 10, < 13)
198
+      ruby-statistics (>= 2.1)
169 199
       thor (~> 0.19)
170
-    devise (4.6.2)
200
+    devise (4.7.1)
171 201
       bcrypt (~> 3.0)
172 202
       orm_adapter (~> 0.1)
173
-      railties (>= 4.1.0, < 6.0)
203
+      railties (>= 4.1.0)
174 204
       responders
175 205
       warden (~> 1.2.3)
176
-    devise-two-factor (3.0.3)
177
-      activesupport (< 5.3)
206
+    devise-two-factor (3.1.0)
207
+      activesupport (< 6.1)
178 208
       attr_encrypted (>= 1.3, < 4, != 2)
179 209
       devise (~> 4.0)
180
-      railties (< 5.3)
210
+      railties (< 6.1)
181 211
       rotp (~> 2.0)
182 212
     devise_pam_authenticatable2 (9.2.0)
183 213
       devise (>= 4.0.0)
184 214
       rpam2 (~> 4.0)
185 215
     diff-lcs (1.3)
186
-    docile (1.3.0)
216
+    discard (1.1.0)
217
+      activerecord (>= 4.2, < 7)
218
+    docile (1.3.2)
187 219
     domain_name (0.5.20180417)
188 220
       unf (>= 0.0.5, < 1.0.0)
189
-    doorkeeper (5.1.0)
221
+    doorkeeper (5.2.1)
190 222
       railties (>= 5)
191
-    dotenv (2.7.2)
192
-    dotenv-rails (2.7.2)
193
-      dotenv (= 2.7.2)
223
+    dotenv (2.7.5)
224
+    dotenv-rails (2.7.5)
225
+      dotenv (= 2.7.5)
194 226
       railties (>= 3.2, < 6.1)
195
-    elasticsearch (6.0.2)
196
-      elasticsearch-api (= 6.0.2)
197
-      elasticsearch-transport (= 6.0.2)
198
-    elasticsearch-api (6.0.2)
227
+    elasticsearch (7.3.0)
228
+      elasticsearch-api (= 7.3.0)
229
+      elasticsearch-transport (= 7.3.0)
230
+    elasticsearch-api (7.3.0)
199 231
       multi_json
200
-    elasticsearch-dsl (0.1.5)
201
-    elasticsearch-transport (6.0.2)
232
+    elasticsearch-dsl (0.1.8)
233
+    elasticsearch-transport (7.3.0)
202 234
       faraday
203 235
       multi_json
204 236
     encryptor (3.0.0)
205
-    equatable (0.5.0)
237
+    equatable (0.6.1)
206 238
     erubi (1.8.0)
207 239
     et-orbi (1.1.6)
208 240
       tzinfo
209 241
     excon (0.62.0)
210 242
     fabrication (2.20.2)
211
-    faker (1.9.3)
212
-      i18n (>= 0.7)
213
-    faraday (0.15.0)
243
+    faker (2.5.0)
244
+      i18n (~> 1.6.0)
245
+    faraday (0.15.4)
214 246
       multipart-post (>= 1.2, < 3)
215 247
     fast_blank (1.0.0)
216
-    fastimage (2.1.5)
248
+    fastimage (2.1.7)
217 249
     ffi (1.10.0)
218 250
     fog-core (2.1.0)
219 251
       builder
@@ -234,7 +266,8 @@ GEM
234 266
     fuubar (2.4.1)
235 267
       rspec-core (~> 3.0)
236 268
       ruby-progressbar (~> 1.4)
237
-    get_process_mem (0.2.3)
269
+    get_process_mem (0.2.4)
270
+      ffi (~> 1.0)
238 271
     globalid (0.4.2)
239 272
       activesupport (>= 4.2.0)
240 273
     goldfinger (2.1.0)
@@ -253,7 +286,7 @@ GEM
253 286
       railties (>= 4.0.1)
254 287
     hamster (3.0.0)
255 288
       concurrent-ruby (~> 1.0)
256
-    hashdiff (0.4.0)
289
+    hashdiff (1.0.0)
257 290
     hashie (3.6.0)
258 291
     heapy (0.1.4)
259 292
     highline (2.0.1)
@@ -269,7 +302,7 @@ GEM
269 302
       domain_name (~> 0.5)
270 303
     http-form_data (2.1.1)
271 304
     http_accept_language (2.1.1)
272
-    httplog (1.3.1)
305
+    httplog (1.3.2)
273 306
       rack (>= 1.0)
274 307
       rainbow (>= 2.0.0)
275 308
     i18n (1.6.0)
@@ -287,17 +320,15 @@ GEM
287 320
     idn-ruby (0.1.0)
288 321
     ipaddress (0.8.3)
289 322
     iso-639 (0.2.8)
290
-    jaro_winkler (1.5.2)
323
+    jaro_winkler (1.5.3)
291 324
     jmespath (1.4.0)
292
-    json (2.1.0)
293
-    json-ld (3.0.2)
294
-      multi_json (~> 1.12)
295
-      rdf (>= 2.2.8, < 4.0)
296
-    json-ld-preloaded (3.0.2)
325
+    json (2.2.0)
326
+    json-canonicalization (0.1.0)
327
+    json-ld-preloaded (3.0.4)
297 328
       json-ld (~> 3.0)
298 329
       multi_json (~> 1.12)
299 330
       rdf (~> 3.0)
300
-    jsonapi-renderer (0.2.0)
331
+    jsonapi-renderer (0.2.2)
301 332
     jwt (2.1.0)
302 333
     kaminari (1.1.1)
303 334
       activesupport (>= 4.1.0)
@@ -336,37 +367,37 @@ GEM
336 367
       mimemagic (~> 0.3.2)
337 368
     mario-redis-lock (1.2.1)
338 369
       redis (>= 3.0.5)
339
-    memory_profiler (0.9.13)
370
+    memory_profiler (0.9.14)
340 371
     method_source (0.9.2)
341 372
     microformats (4.1.0)
342 373
       json (~> 2.1)
343 374
       nokogiri (~> 1.8, >= 1.8.3)
344
-    mime-types (3.2.2)
375
+    mime-types (3.3)
345 376
       mime-types-data (~> 3.2015)
346
-    mime-types-data (3.2018.0812)
377
+    mime-types-data (3.2019.0904)
347 378
     mimemagic (0.3.3)
348
-    mini_mime (1.0.1)
379
+    mini_mime (1.0.2)
349 380
     mini_portile2 (2.4.0)
350
-    minitest (5.11.3)
351
-    msgpack (1.2.10)
381
+    minitest (5.12.0)
382
+    msgpack (1.3.1)
352 383
     multi_json (1.13.1)
353
-    multipart-post (2.0.0)
384
+    multipart-post (2.1.1)
354 385
     necromancer (0.5.0)
355 386
     net-ldap (0.16.1)
356
-    net-scp (1.2.1)
357
-      net-ssh (>= 2.6.5)
358
-    net-ssh (5.0.2)
359
-    nio4r (2.3.1)
360
-    nokogiri (1.10.3)
387
+    net-scp (2.0.0)
388
+      net-ssh (>= 2.6.5, < 6.0.0)
389
+    net-ssh (5.2.0)
390
+    nio4r (2.5.1)
391
+    nokogiri (1.10.4)
361 392
       mini_portile2 (~> 2.4.0)
362
-    nokogumbo (2.0.0)
393
+    nokogumbo (2.0.1)
363 394
       nokogiri (~> 1.8, >= 1.8.4)
364 395
     nsa (0.2.7)
365 396
       activesupport (>= 4.2, < 6)
366 397
       concurrent-ruby (~> 1.0, >= 1.0.2)
367 398
       sidekiq (>= 3.5)
368 399
       statsd-ruby (~> 1.4, >= 1.4.0)
369
-    oj (3.7.12)
400
+    oj (3.9.1)
370 401
     omniauth (1.9.0)
371 402
       hashie (>= 3.4.6, < 3.7.0)
372 403
       rack (>= 1.6.2, < 3)
@@ -393,23 +424,24 @@ GEM
393 424
       av (~> 0.9.0)
394 425
       paperclip (>= 2.5.2)
395 426
     parallel (1.17.0)
396
-    parallel_tests (2.29.0)
427
+    parallel_tests (2.29.2)
397 428
       parallel
398
-    parser (2.6.3.0)
429
+    parser (2.6.4.0)
399 430
       ast (~> 2.4.0)
400
-    pastel (0.7.2)
401
-      equatable (~> 0.5.0)
402
-      tty-color (~> 0.4.0)
431
+    parslet (1.8.2)
432
+    pastel (0.7.3)
433
+      equatable (~> 0.6)
434
+      tty-color (~> 0.5)
403 435
     pg (1.1.4)
404
-    pghero (2.2.1)
405
-      activerecord
406
-    pkg-config (1.3.7)
436
+    pghero (2.3.0)
437
+      activerecord (>= 5)
438
+    pkg-config (1.3.9)
407 439
     premailer (1.11.1)
408 440
       addressable
409 441
       css_parser (>= 1.6.0)
410 442
       htmlentities (>= 4.0.0)
411
-    premailer-rails (1.10.2)
412
-      actionmailer (>= 3, < 6)
443
+    premailer-rails (1.10.3)
444
+      actionmailer (>= 3)
413 445
       premailer (~> 1.7, >= 1.7.9)
414 446
     private_address_check (0.5.0)
415 447
     pry (0.12.2)
@@ -420,13 +452,14 @@ GEM
420 452
       pry (~> 0.10)
421 453
     pry-rails (0.3.9)
422 454
       pry (>= 0.10.4)
423
-    public_suffix (3.1.0)
424
-    puma (3.12.1)
425
-    pundit (2.0.1)
455
+    public_suffix (4.0.1)
456
+    puma (4.2.0)
457
+      nio4r (~> 2.0)
458
+    pundit (2.1.0)
426 459
       activesupport (>= 3.0.0)
427 460
     raabro (1.1.6)
428 461
     rack (2.0.7)
429
-    rack-attack (6.0.0)
462
+    rack-attack (6.1.0)
430 463
       rack (>= 1.0, < 3)
431 464
     rack-cors (1.0.3)
432 465
     rack-protection (2.0.5)
@@ -455,7 +488,7 @@ GEM
455 488
     rails-dom-testing (2.0.3)
456 489
       activesupport (>= 4.2.0)
457 490
       nokogiri (>= 1.6)
458
-    rails-html-sanitizer (1.0.4)
491
+    rails-html-sanitizer (1.2.0)
459 492
       loofah (~> 2.2, >= 2.2.2)
460 493
     rails-i18n (5.1.3)
461 494
       i18n (>= 0.7, < 2)
@@ -469,13 +502,13 @@ GEM
469 502
       rake (>= 0.8.7)
470 503
       thor (>= 0.19.0, < 2.0)
471 504
     rainbow (3.0.0)
472
-    rake (12.3.2)
473
-    rdf (3.0.9)
505
+    rake (12.3.3)
506
+    rdf (3.0.12)
474 507
       hamster (~> 3.0)
475 508
       link_header (~> 0.0, >= 0.0.8)
476 509
     rdf-normalize (0.3.3)
477 510
       rdf (>= 2.2, < 4.0)
478
-    redis (4.1.2)
511
+    redis (4.1.3)
479 512
     redis-actionpack (5.0.2)
480 513
       actionpack (>= 4.0, < 6)
481 514
       redis-rack (>= 1, < 3)
@@ -494,12 +527,12 @@ GEM
494 527
       redis-store (>= 1.2, < 2)
495 528
     redis-store (1.5.0)
496 529
       redis (>= 2.2, < 5)
497
-    regexp_parser (1.5.1)
530
+    regexp_parser (1.6.0)
498 531
     request_store (1.4.1)
499 532
       rack (>= 1.4)
500
-    responders (2.4.1)
501
-      actionpack (>= 4.2.0, < 6.0)
502
-      railties (>= 4.2.0, < 6.0)
533
+    responders (3.0.0)
534
+      actionpack (>= 5.0)
535
+      railties (>= 5.0)
503 536
     rotp (2.1.2)
504 537
     rpam2 (4.0.2)
505 538
     rqrcode (0.10.1)
@@ -524,23 +557,24 @@ GEM
524 557
       rspec-core (~> 3.0, >= 3.0.0)
525 558
       sidekiq (>= 2.4.0)
526 559
     rspec-support (3.8.0)
527
-    rubocop (0.71.0)
560
+    rubocop (0.74.0)
528 561
       jaro_winkler (~> 1.5.1)
529 562
       parallel (~> 1.10)
530 563
       parser (>= 2.6)
531 564
       rainbow (>= 2.2.2, < 4.0)
532 565
       ruby-progressbar (~> 1.7)
533 566
       unicode-display_width (>= 1.4.0, < 1.7)
534
-    rubocop-rails (2.0.1)
567
+    rubocop-rails (2.3.2)
535 568
       rack (>= 1.1)
536
-      rubocop (>= 0.70.0)
569
+      rubocop (>= 0.72.0)
537 570
     ruby-progressbar (1.10.1)
538 571
     ruby-saml (1.9.0)
539 572
       nokogiri (>= 1.5.10)
573
+    ruby-statistics (2.1.1)
540 574
     rufus-scheduler (3.5.2)
541 575
       fugit (~> 1.1, >= 1.1.5)
542 576
     safe_yaml (1.0.5)
543
-    sanitize (5.0.0)
577
+    sanitize (5.1.0)
544 578
       crass (~> 1.0.2)
545 579
       nokogiri (>= 1.8.0)
546 580
       nokogumbo (~> 2.0)
@@ -560,12 +594,12 @@ GEM
560 594
       concurrent-ruby (~> 1.0, >= 1.0.5)
561 595
       sidekiq (>= 4.0, < 7.0)
562 596
       thor (~> 0)
563
-    simple-navigation (4.0.5)
597
+    simple-navigation (4.1.0)
564 598
       activesupport (>= 2.3.2)
565 599
     simple_form (4.1.0)
566 600
       actionpack (>= 5.0)
567 601
       activemodel (>= 5.0)
568
-    simplecov (0.16.1)
602
+    simplecov (0.17.1)
569 603
       docile (~> 1.1)
570 604
       json (>= 1.8, < 3)
571 605
       simplecov-html (~> 0.10.0)
@@ -577,7 +611,7 @@ GEM
577 611
       actionpack (>= 4.0)
578 612
       activesupport (>= 4.0)
579 613
       sprockets (>= 3.0.0)
580
-    sshkit (1.17.0)
614
+    sshkit (1.20.0)
581 615
       net-scp (>= 1.1.2)
582 616
       net-ssh (>= 2.8.0)
583 617
     stackprof (0.2.12)
@@ -585,7 +619,7 @@ GEM
585 619
     stoplight (2.1.3)
586 620
     streamio-ffmpeg (3.0.2)
587 621
       multi_json (~> 1.8)
588
-    strong_migrations (0.4.0)
622
+    strong_migrations (0.4.1)
589 623
       activerecord (>= 5)
590 624
     temple (0.8.1)
591 625
     terminal-table (1.8.0)
@@ -595,8 +629,8 @@ GEM
595 629
     thor (0.20.3)
596 630
     thread_safe (0.3.6)
597 631
     tilt (2.0.9)
598
-    tty-color (0.4.3)
599
-    tty-command (0.8.2)
632
+    tty-color (0.5.0)
633
+    tty-command (0.9.0)
600 634
       pastel (~> 0.7.0)
601 635
     tty-cursor (0.7.0)
602 636
     tty-prompt (0.19.0)
@@ -612,7 +646,7 @@ GEM
612 646
       unf (~> 0.1.0)
613 647
     tzinfo (1.2.5)
614 648
       thread_safe (~> 0.1)
615
-    tzinfo-data (1.2019.1)
649
+    tzinfo-data (1.2019.3)
616 650
       tzinfo (>= 1.0.0)
617 651
     unf (0.1.4)
618 652
       unf_ext
@@ -621,7 +655,7 @@ GEM
621 655
     uniform_notifier (1.12.1)
622 656
     warden (1.2.8)
623 657
       rack (>= 2.0.6)
624
-    webmock (3.6.0)
658
+    webmock (3.7.6)
625 659
       addressable (>= 2.3.6)
626 660
       crack (>= 0.3.2)
627 661
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -645,14 +679,14 @@ PLATFORMS
645 679
 DEPENDENCIES
646 680
   active_model_serializers (~> 0.10)
647 681
   active_record_query_trace (~> 1.6)
648
-  addressable (~> 2.6)
682
+  addressable (~> 2.7)
649 683
   annotate (~> 2.7)
650
-  aws-sdk-s3 (~> 1.42)
684
+  aws-sdk-s3 (~> 1.48)
651 685
   better_errors (~> 2.5)
652 686
   binding_of_caller (~> 0.7)
653 687
   blurhash (~> 0.1)
654 688
   bootsnap (~> 1.4)
655
-  brakeman (~> 4.5)
689
+  brakeman (~> 4.6)
656 690
   browser
657 691
   bullet (~> 6.0)
658 692
   bundler-audit (~> 0.6)
@@ -660,20 +694,22 @@ DEPENDENCIES
660 694
   capistrano-rails (~> 1.4)
661 695
   capistrano-rbenv (~> 2.1)
662 696
   capistrano-yarn (~> 2.0)
663
-  capybara (~> 3.24)
697
+  capybara (~> 3.29)
664 698
   charlock_holmes (~> 0.7.6)
665
-  chewy (~> 5.0)
699
+  chewy (~> 5.1)
666 700
   cld3 (~> 3.2.4)
667 701
   climate_control (~> 0.2)
668 702
   concurrent-ruby
703
+  connection_pool
669 704
   derailed_benchmarks
670
-  devise (~> 4.6)
671
-  devise-two-factor (~> 3.0)
705
+  devise (~> 4.7)
706
+  devise-two-factor (~> 3.1)
672 707
   devise_pam_authenticatable2 (~> 9.2)
673
-  doorkeeper (~> 5.1)
708
+  discard (~> 1.1)
709
+  doorkeeper (~> 5.2)
674 710
   dotenv-rails (~> 2.7)
675 711
   fabrication (~> 2.20)
676
-  faker (~> 1.9)
712
+  faker (~> 2.5)
677 713
   fast_blank (~> 1.0)
678 714
   fastimage
679 715
   fog-core (<= 2.1.0)
@@ -681,6 +717,7 @@ DEPENDENCIES
681 717
   fuubar (~> 2.4)
682 718
   goldfinger (~> 2.1)
683 719
   hamlit-rails (~> 0.2)
720
+  health_check!
684 721
   hiredis (~> 0.6)
685 722
   htmlentities (~> 4.3)
686 723
   http (~> 3.3)
@@ -690,7 +727,7 @@ DEPENDENCIES
690 727
   i18n-tasks (~> 0.9)
691 728
   idn-ruby
692 729
   iso-639
693
-  json-ld (~> 3.0)
730
+  json-ld!
694 731
   json-ld-preloaded (~> 3.0)
695 732
   kaminari (~> 1.1)
696 733
   letter_opener (~> 1.7)
@@ -701,11 +738,12 @@ DEPENDENCIES
701 738
   mario-redis-lock (~> 1.2)
702 739
   memory_profiler
703 740
   microformats (~> 4.1)
704
-  mime-types (~> 3.2)
741
+  mime-types (~> 3.3)
705 742
   net-ldap (~> 0.10)
743
+  nilsimsa!
706 744
   nokogiri (~> 1.10)
707 745
   nsa (~> 0.2)
708
-  oj (~> 3.7)
746
+  oj (~> 3.9)
709 747
   omniauth (~> 1.9)
710 748
   omniauth-cas (~> 1.1)
711 749
   omniauth-saml (~> 1.10)
@@ -713,18 +751,20 @@ DEPENDENCIES
713 751
   ox (~> 2.11)
714 752
   paperclip (~> 6.0)
715 753
   paperclip-av-transcoder (~> 0.6)
754
+  parallel (~> 1.17)
716 755
   parallel_tests (~> 2.29)
756
+  parslet
717 757
   pg (~> 1.1)
718
-  pghero (~> 2.2)
758
+  pghero (~> 2.3)
719 759
   pkg-config (~> 1.3)
720 760
   posix-spawn!
721 761
   premailer-rails
722 762
   private_address_check (~> 0.5)
723 763
   pry-byebug (~> 3.7)
724 764
   pry-rails (~> 0.3)
725
-  puma (~> 3.12)
726
-  pundit (~> 2.0)
727
-  rack-attack (~> 6.0)
765
+  puma (~> 4.2)
766
+  pundit (~> 2.1)
767
+  rack-attack (~> 6.1)
728 768
   rack-cors (~> 1.0)
729 769
   rails (~> 5.2.3)
730 770
   rails-controller-testing (~> 1.0)
@@ -737,32 +777,33 @@ DEPENDENCIES
737 777
   rqrcode (~> 0.10)
738 778
   rspec-rails (~> 3.8)
739 779
   rspec-sidekiq (~> 3.0)
740
-  rubocop (~> 0.71)
741
-  rubocop-rails (~> 2.0)
742
-  sanitize (~> 5.0)
780
+  rubocop (~> 0.74)
781
+  rubocop-rails (~> 2.3)
782
+  ruby-progressbar (~> 1.10)
783
+  sanitize (~> 5.1)
743 784
   sidekiq (~> 5.2)
744 785
   sidekiq-bulk (~> 0.2.0)
745 786
   sidekiq-scheduler (~> 3.0)
746 787
   sidekiq-unique-jobs (~> 6.0)
747
-  simple-navigation (~> 4.0)
788
+  simple-navigation (~> 4.1)
748 789
   simple_form (~> 4.1)
749
-  simplecov (~> 0.16)
790
+  simplecov (~> 0.17)
750 791
   sprockets-rails (~> 3.2)
751 792
   stackprof
752 793
   stoplight (~> 2.1.3)
753 794
   streamio-ffmpeg (~> 3.0)
754 795
   strong_migrations (~> 0.4)
755 796
   thor (~> 0.20)
756
-  tty-command (~> 0.8)
797
+  tty-command (~> 0.9)
757 798
   tty-prompt (~> 0.19)
758 799
   twitter-text (~> 1.14)
759 800
   tzinfo-data (~> 1.2019)
760
-  webmock (~> 3.6)
801
+  webmock (~> 3.7)
761 802
   webpacker (~> 4.0)
762 803
   webpush
763 804
 
764 805
 RUBY VERSION
765
-   ruby 2.6.1p33
806
+   ruby 2.6.5p114
766 807
 
767 808
 BUNDLED WITH
768 809
    1.17.3

+ 1
- 1
README.md View File

@@ -55,7 +55,7 @@ Private posts, locked accounts, phrase filtering, muting, blocking and all sorts
55 55
 
56 56
 **OAuth2 and a straightforward REST API**
57 57
 
58
-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!
58
+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!
59 59
 
60 60
 ## Deployment
61 61
 

+ 0
- 9
app.json View File

@@ -13,15 +13,6 @@
13 13
       "description": "The domain that your Mastodon instance will run on (this can be appname.herokuapp.com or a custom domain)",
14 14
       "required": true
15 15
     },
16
-    "LOCAL_HTTPS": {
17
-      "description": "Will your domain support HTTPS? (Automatic for herokuapp, requires manual configuration for custom domains)",
18
-      "value": "false",
19
-      "required": true
20
-    },
21
-    "PAPERCLIP_SECRET": {
22
-      "description": "The secret key for storing media files",
23
-      "generator": "secret"
24
-    },
25 16
     "SECRET_KEY_BASE": {
26 17
       "description": "The secret key base",
27 18
       "generator": "secret"

+ 43
- 0
app/chewy/accounts_index.rb View File

@@ -0,0 +1,43 @@
1
+# frozen_string_literal: true
2
+
3
+class AccountsIndex < Chewy::Index
4
+  settings index: { refresh_interval: '5m' }, analysis: {
5
+    analyzer: {
6
+      content: {
7
+        tokenizer: 'whitespace',
8
+        filter: %w(lowercase asciifolding cjk_width),
9
+      },
10
+
11
+      edge_ngram: {
12
+        tokenizer: 'edge_ngram',
13
+        filter: %w(lowercase asciifolding cjk_width),
14
+      },
15
+    },
16
+
17
+    tokenizer: {
18
+      edge_ngram: {
19
+        type: 'edge_ngram',
20
+        min_gram: 1,
21
+        max_gram: 15,
22
+      },
23
+    },
24
+  }
25
+
26
+  define_type ::Account.searchable.includes(:account_stat), delete_if: ->(account) { account.destroyed? || !account.searchable? } do
27
+    root date_detection: false do
28
+      field :id, type: 'long'
29
+
30
+      field :display_name, type: 'text', analyzer: 'content' do
31
+        field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content'
32
+      end
33
+
34
+      field :acct, type: 'text', analyzer: 'content', value: ->(account) { [account.username, account.domain].compact.join('@') } do
35
+        field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content'
36
+      end
37
+
38
+      field :following_count, type: 'long', value: ->(account) { account.following.local.count }
39
+      field :followers_count, type: 'long', value: ->(account) { account.followers.local.count }
40
+      field :last_status_at, type: 'date', value: ->(account) { account.last_status_at || account.created_at }
41
+    end
42
+  end
43
+end

+ 5
- 5
app/chewy/statuses_index.rb View File

@@ -31,19 +31,19 @@ class StatusesIndex < Chewy::Index
31 31
     },
32 32
   }
33 33
 
34
-  define_type ::Status.unscoped.without_reblogs.includes(:media_attachments) do
34
+  define_type ::Status.unscoped.kept.without_reblogs.includes(:media_attachments), delete_if: ->(status) { status.searchable_by.empty? } do
35 35
     crutch :mentions do |collection|
36
-      data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
36
+      data = ::Mention.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
37 37
       data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
38 38
     end
39 39
 
40 40
     crutch :favourites do |collection|
41
-      data = ::Favourite.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
41
+      data = ::Favourite.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
42 42
       data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
43 43
     end
44 44
 
45 45
     crutch :reblogs do |collection|
46
-      data = ::Status.where(reblog_of_id: collection.map(&:id)).pluck(:reblog_of_id, :account_id)
46
+      data = ::Status.where(reblog_of_id: collection.map(&:id)).where(account: Account.local).pluck(:reblog_of_id, :account_id)
47 47
       data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
48 48
     end
49 49
 
@@ -51,7 +51,7 @@ class StatusesIndex < Chewy::Index
51 51
       field :id, type: 'long'
52 52
       field :account_id, type: 'long'
53 53
 
54
-      field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).concat(status.preloadable_poll ? status_preloadable_poll.options : []).join("\n\n") } do
54
+      field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).concat(status.preloadable_poll ? status.preloadable_poll.options : []).join("\n\n") } do
55 55
         field :stemmed, type: 'text', analyzer: 'content'
56 56
       end
57 57
 

+ 37
- 0
app/chewy/tags_index.rb View File

@@ -0,0 +1,37 @@
1
+# frozen_string_literal: true
2
+
3
+class TagsIndex < Chewy::Index
4
+  settings index: { refresh_interval: '15m' }, analysis: {
5
+    analyzer: {
6
+      content: {
7
+        tokenizer: 'keyword',
8
+        filter: %w(lowercase asciifolding cjk_width),
9
+      },
10
+
11
+      edge_ngram: {
12
+        tokenizer: 'edge_ngram',
13
+        filter: %w(lowercase asciifolding cjk_width),
14
+      },
15
+    },
16
+
17
+    tokenizer: {
18
+      edge_ngram: {
19
+        type: 'edge_ngram',
20
+        min_gram: 2,
21
+        max_gram: 15,
22
+      },
23
+    },
24
+  }
25
+
26
+  define_type ::Tag.listable, delete_if: ->(tag) { tag.destroyed? || !tag.listable? } do
27
+    root date_detection: false do
28
+      field :name, type: 'text', analyzer: 'content' do
29
+        field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content'
30
+      end
31
+
32
+      field :reviewed, type: 'boolean', value: ->(tag) { tag.reviewed? }
33
+      field :usage, type: 'long', value: ->(tag) { tag.history.reduce(0) { |total, day| total + day[:accounts].to_i } }
34
+      field :last_status_at, type: 'date', value: ->(tag) { tag.last_status_at || tag.created_at }
35
+    end
36
+  end
37
+end

+ 40
- 8
app/controllers/about_controller.rb View File

@@ -3,20 +3,46 @@
3 3
 class AboutController < ApplicationController
4 4
   layout 'public'
5 5
 
6
-  before_action :set_instance_presenter, only: [:show, :more, :terms]
6
+  before_action :require_open_federation!, only: [:show, :more]
7
+  before_action :set_body_classes, only: :show
8
+  before_action :set_instance_presenter
9
+  before_action :set_expires_in, only: [:show, :more, :terms]
7 10
 
8
-  skip_before_action :check_user_permissions, only: [:more, :terms]
11
+  skip_before_action :require_functional!, only: [:more, :terms]
9 12
 
10
-  def show
11
-    @hide_navbar = true
12
-  end
13
+  def show; end
14
+
15
+  def more
16
+    flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
13 17
 
14
-  def more; end
18
+    toc_generator = TOCGenerator.new(@instance_presenter.site_extended_description)
19
+
20
+    @contents          = toc_generator.html
21
+    @table_of_contents = toc_generator.toc
22
+    @blocks            = DomainBlock.with_user_facing_limitations.by_severity if display_blocks?
23
+  end
15 24
 
16 25
   def terms; end
17 26
 
27
+  helper_method :display_blocks?
28
+  helper_method :display_blocks_rationale?
29
+  helper_method :public_fetch_mode?
30
+  helper_method :new_user
31
+
18 32
   private
19 33
 
34
+  def require_open_federation!
35
+    not_found if whitelist_mode?
36
+  end
37
+
38
+  def display_blocks?
39
+    Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
40
+  end
41
+
42
+  def display_blocks_rationale?
43
+    Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)
44
+  end
45
+
20 46
   def new_user
21 47
     User.new.tap do |user|
22 48
       user.build_account
@@ -24,9 +50,15 @@ class AboutController < ApplicationController
24 50
     end
25 51
   end
26 52
 
27
-  helper_method :new_user
28
-
29 53
   def set_instance_presenter
30 54
     @instance_presenter = InstancePresenter.new
31 55
   end
56
+
57
+  def set_body_classes
58
+    @hide_navbar = true
59
+  end
60
+
61
+  def set_expires_in
62
+    expires_in 0, public: true
63
+  end
32 64
 end

+ 37
- 18
app/controllers/accounts_controller.rb View File

@@ -4,17 +4,22 @@ class AccountsController < ApplicationController
4 4
   PAGE_SIZE = 20
5 5
 
6 6
   include AccountControllerConcern
7
+  include SignatureAuthentication
7 8
 
8 9
   before_action :set_cache_headers
10
+  before_action :set_body_classes
11
+
12
+  skip_around_action :set_locale, if: -> { [:json, :rss].include?(request.format) }
13
+  skip_before_action :require_functional!
9 14
 
10 15
   def show
11 16
     respond_to do |format|
12 17
       format.html do
13
-        mark_cacheable! unless user_signed_in?
18
+        expires_in 0, public: true unless user_signed_in?
14 19
 
15
-        @body_classes      = 'with-modals'
16 20
         @pinned_statuses   = []
17 21
         @endorsed_accounts = @account.endorsed_accounts.to_a.sample(4)
22
+        @featured_hashtags = @account.featured_tags.order(statuses_count: :desc)
18 23
 
19 24
         if current_account && @account.blocking?(current_account)
20 25
           @statuses = []
@@ -24,6 +29,7 @@ class AccountsController < ApplicationController
24 29
         @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
25 30
         @statuses        = filtered_status_page(params)
26 31
         @statuses        = cache_collection(@statuses, Status)
32
+        @rss_url         = rss_url
27 33
 
28 34
         unless @statuses.empty?
29 35
           @older_url = older_url if @statuses.last.id > filtered_statuses.last.id
@@ -31,30 +37,27 @@ class AccountsController < ApplicationController
31 37
         end
32 38
       end
33 39
 
34
-      format.atom do
35
-        mark_cacheable!
36
-
37
-        @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id])
38
-        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? }))
39
-      end
40
-
41 40
       format.rss do
42
-        mark_cacheable!
41
+        expires_in 1.minute, public: true
43 42
 
44
-        @statuses = cache_collection(default_statuses.without_reblogs.without_replies.limit(PAGE_SIZE), Status)
45
-        render xml: RSS::AccountSerializer.render(@account, @statuses)
43
+        @statuses = filtered_statuses.without_reblogs.without_replies.limit(PAGE_SIZE)
44
+        @statuses = cache_collection(@statuses, Status)
45
+        render xml: RSS::AccountSerializer.render(@account, @statuses, params[:tag])
46 46
       end
47 47
 
48 48
       format.json do
49
-        render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do
50
-          ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter)
51
-        end
49
+        expires_in 3.minutes, public: !(authorized_fetch_mode? && signed_request_account.present?)
50
+        render_with_cache json: @account, content_type: 'application/activity+json', serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, fields: restrict_fields_to
52 51
       end
53 52
     end
54 53
   end
55 54
 
56 55
   private
57 56
 
57
+  def set_body_classes
58
+    @body_classes = 'with-modals'
59
+  end
60
+
58 61
   def show_pinned_statuses?
59 62
     [replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none?
60 63
   end
@@ -97,6 +100,14 @@ class AccountsController < ApplicationController
97 100
     params[:username]
98 101
   end
99 102
 
103
+  def rss_url
104
+    if tag_requested?
105
+      short_account_tag_url(@account, params[:tag], format: 'rss')
106
+    else
107
+      short_account_url(@account, format: 'rss')
108
+    end
109
+  end
110
+
100 111
   def older_url
101 112
     pagination_url(max_id: @statuses.last.id)
102 113
   end
@@ -118,15 +129,15 @@ class AccountsController < ApplicationController
118 129
   end
119 130
 
120 131
   def media_requested?
121
-    request.path.ends_with?('/media')
132
+    request.path.ends_with?('/media') && !tag_requested?
122 133
   end
123 134
 
124 135
   def replies_requested?
125
-    request.path.ends_with?('/with_replies')
136
+    request.path.ends_with?('/with_replies') && !tag_requested?
126 137
   end
127 138
 
128 139
   def tag_requested?
129
-    request.path.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
140
+    request.path.split('.').first.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
130 141
   end
131 142
 
132 143
   def filtered_status_page(params)
@@ -136,4 +147,12 @@ class AccountsController < ApplicationController
136 147
       filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a
137 148
     end
138 149
   end
150
+
151
+  def restrict_fields_to
152
+    if signed_request_account.present? || public_fetch_mode?
153
+      # Return all fields
154
+    else
155
+      %i(id type preferred_username inbox public_key endpoints)
156
+    end
157
+  end
139 158
 end

+ 11
- 0
app/controllers/activitypub/base_controller.rb View File

@@ -0,0 +1,11 @@
1
+# frozen_string_literal: true
2
+
3
+class ActivityPub::BaseController < Api::BaseController
4
+  skip_before_action :require_authenticated_user!
5
+
6
+  private
7
+
8
+  def set_cache_headers
9
+    response.headers['Vary'] = 'Signature' if authorized_fetch_mode?
10
+  end
11
+end

+ 8
- 17
app/controllers/activitypub/collections_controller.rb View File

@@ -1,30 +1,21 @@
1 1
 # frozen_string_literal: true
2 2
 
3
-class ActivityPub::CollectionsController < Api::BaseController
3
+class ActivityPub::CollectionsController < ActivityPub::BaseController
4 4
   include SignatureVerification
5
+  include AccountOwnedConcern
5 6
 
6
-  before_action :set_account
7
+  before_action :require_signature!, if: :authorized_fetch_mode?
7 8
   before_action :set_size
8 9
   before_action :set_statuses
9 10
   before_action :set_cache_headers
10 11
 
11 12
   def show
12
-    render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
13
-      ActiveModelSerializers::SerializableResource.new(
14
-        collection_presenter,
15
-        serializer: ActivityPub::CollectionSerializer,
16
-        adapter: ActivityPub::Adapter,
17
-        skip_activities: true
18
-      )
19
-    end
13
+    expires_in 3.minutes, public: public_fetch_mode?
14
+    render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true
20 15
   end
21 16
 
22 17
   private
23 18
 
24
-  def set_account
25
-    @account = Account.find_local!(params[:account_username])
26
-  end
27
-
28 19
   def set_statuses
29 20
     @statuses = scope_for_collection
30 21
     @statuses = cache_collection(@statuses, Status)
@@ -42,9 +33,9 @@ class ActivityPub::CollectionsController < Api::BaseController
42 33
   def scope_for_collection
43 34
     case params[:id]
44 35
     when 'featured'
45
-      @account.statuses.permitted_for(@account, signed_request_account).tap do |scope|
46
-        scope.merge!(@account.pinned_statuses)
47
-      end
36
+      return Status.none if @account.blocking?(signed_request_account)
37
+
38
+      @account.pinned_statuses
48 39
     else
49 40
       raise ActiveRecord::RecordNotFound
50 41
     end

+ 19
- 16
app/controllers/activitypub/inboxes_controller.rb View File

@@ -1,40 +1,44 @@
1 1
 # frozen_string_literal: true
2 2
 
3
-class ActivityPub::InboxesController < Api::BaseController
3
+class ActivityPub::InboxesController < ActivityPub::BaseController
4 4
   include SignatureVerification
5 5
   include JsonLdHelper
6
+  include AccountOwnedConcern
6 7
 
7
-  before_action :set_account
8
+  before_action :skip_unknown_actor_delete
9
+  before_action :require_signature!
8 10
 
9 11
   def create
10
-    if unknown_deleted_account?
11
-      head 202
12
-    elsif signed_request_account
13
-      upgrade_account
14
-      process_payload
15
-      head 202
16
-    else
17
-      render plain: signature_verification_failure_reason, status: 401
18
-    end
12
+    upgrade_account
13
+    process_payload
14
+    head 202
19 15
   end
20 16
 
21 17
   private
22 18
 
19
+  def skip_unknown_actor_delete
20
+    head 202 if unknown_deleted_account?
21
+  end
22
+
23 23
   def unknown_deleted_account?
24 24
     json = Oj.load(body, mode: :strict)
25
-    json['type'] == 'Delete' && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists?
25
+    json.is_a?(Hash) && json['type'] == 'Delete' && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists?
26 26
   rescue Oj::ParseError
27 27
     false
28 28
   end
29 29
 
30
-  def set_account
31
-    @account = Account.find_local!(params[:account_username]) if params[:account_username]
30
+  def account_required?
31
+    params[:account_username].present?
32 32
   end
33 33
 
34 34
   def body
35 35
     return @body if defined?(@body)
36
-    @body = request.body.read.force_encoding('UTF-8')
36
+
37
+    @body = request.body.read
38
+    @body.force_encoding('UTF-8') if @body.present?
39
+
37 40
     request.body.rewind if request.body.respond_to?(:rewind)
41
+
38 42
     @body
39 43
   end
40 44
 
@@ -44,7 +48,6 @@ class ActivityPub::InboxesController < Api::BaseController
44 48
       ResolveAccountWorker.perform_async(signed_request_account.acct)
45 49
     end
46 50
 
47
-    Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?
48 51
     DeliveryFailureTracker.track_inverse_success!(signed_request_account)
49 52
   end
50 53
 

+ 4
- 8
app/controllers/activitypub/outboxes_controller.rb View File

@@ -1,26 +1,22 @@
1 1
 # frozen_string_literal: true
2 2
 
3
-class ActivityPub::OutboxesController < Api::BaseController
3
+class ActivityPub::OutboxesController < ActivityPub::BaseController
4 4
   LIMIT = 20
5 5
 
6 6
   include SignatureVerification
7
+  include AccountOwnedConcern
7 8
 
8
-  before_action :set_account
9
+  before_action :require_signature!, if: :authorized_fetch_mode?
9 10
   before_action :set_statuses
10 11
   before_action :set_cache_headers
11 12
 
12 13
   def show
13
-    expires_in 1.minute, public: true unless page_requested?
14
-
14
+    expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
15 15
     render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
16 16
   end
17 17
 
18 18
   private
19 19
 
20
-  def set_account
21
-    @account = Account.find_local!(params[:account_username])
22
-  end
23
-
24 20
   def outbox_presenter
25 21
     if page_requested?
26 22
       ActivityPub::CollectionPresenter.new(

+ 71
- 0
app/controllers/activitypub/replies_controller.rb View File

@@ -0,0 +1,71 @@
1
+# frozen_string_literal: true
2
+
3
+class ActivityPub::RepliesController < ActivityPub::BaseController
4
+  include SignatureAuthentication
5
+  include Authorization
6
+  include AccountOwnedConcern
7
+
8
+  DESCENDANTS_LIMIT = 60
9
+
10
+  before_action :require_signature!, if: :authorized_fetch_mode?
11
+  before_action :set_status
12
+  before_action :set_cache_headers
13
+  before_action :set_replies
14
+
15
+  def index
16
+    expires_in 0, public: public_fetch_mode?
17
+    render json: replies_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json', skip_activities: true
18
+  end
19
+
20
+  private
21
+
22
+  def set_status
23
+    @status = @account.statuses.find(params[:status_id])
24
+    authorize @status, :show?
25
+  rescue Mastodon::NotPermittedError
26
+    raise ActiveRecord::RecordNotFound
27
+  end
28
+
29
+  def set_replies
30
+    @replies = page_params[:only_other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses
31
+    @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
32
+    @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
33
+  end
34
+
35
+  def replies_collection_presenter
36
+    page = ActivityPub::CollectionPresenter.new(
37
+      id: account_status_replies_url(@account, @status, page_params),
38
+      type: :unordered,
39
+      part_of: account_status_replies_url(@account, @status),
40
+      next: next_page,
41
+      items: @replies.map { |status| status.local ? status : status.uri }
42
+    )
43
+
44
+    return page if page_requested?
45
+
46
+    ActivityPub::CollectionPresenter.new(
47
+      id: account_status_replies_url(@account, @status),
48
+      type: :unordered,
49
+      first: page
50
+    )
51
+  end
52
+
53
+  def page_requested?
54
+    params[:page] == 'true'
55
+  end
56
+
57
+  def next_page
58
+    only_other_accounts = !(@replies&.last&.account_id == @account.id && @replies.size == DESCENDANTS_LIMIT)
59
+    account_status_replies_url(
60
+      @account,
61
+      @status,
62
+      page: true,
63
+      min_id: only_other_accounts && !page_params[:only_other_accounts] ? nil : @replies&.last&.id,
64
+      only_other_accounts: only_other_accounts
65
+    )
66
+  end
67
+
68
+  def page_params
69
+    params_slice(:only_other_accounts, :min_id).merge(page: true)
70
+  end
71
+end

+ 2
- 2
app/controllers/admin/account_actions_controller.rb View File

@@ -5,7 +5,7 @@ module Admin
5 5
     before_action :set_account
6 6
 
7 7
     def new
8
-      @account_action  = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true)
8
+      @account_action  = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true, include_statuses: true)
9 9
       @warning_presets = AccountWarningPreset.all
10 10
     end
11 11
 
@@ -30,7 +30,7 @@ module Admin
30 30
     end
31 31
 
32 32
     def resource_params
33
-      params.require(:admin_account_action).permit(:type, :report_id, :warning_preset_id, :text, :send_email_notification)
33
+      params.require(:admin_account_action).permit(:type, :report_id, :warning_preset_id, :text, :send_email_notification, :include_statuses)
34 34
     end
35 35
   end
36 36
 end

+ 3
- 15
app/controllers/admin/accounts_controller.rb View File

@@ -2,8 +2,8 @@
2 2
 
3 3
 module Admin
4 4
   class AccountsController < BaseController
5
-    before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
6
-    before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
5
+    before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
6
+    before_action :require_remote_account!, only: [:redownload]
7 7
     before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
8 8
 
9 9
     def index
@@ -19,18 +19,6 @@ module Admin
19 19
       @warnings                = @account.targeted_account_warnings.latest.custom
20 20
     end
21 21
 
22
-    def subscribe
23
-      authorize @account, :subscribe?
24
-      Pubsubhubbub::SubscribeWorker.perform_async(@account.id)
25
-      redirect_to admin_account_path(@account.id)
26
-    end
27
-
28
-    def unsubscribe
29
-      authorize @account, :unsubscribe?
30
-      Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id)
31
-      redirect_to admin_account_path(@account.id)
32
-    end
33
-
34 22
     def memorialize
35 23
       authorize @account, :memorialize?
36 24
       @account.memorialize!
@@ -53,7 +41,7 @@ module Admin
53 41
 
54 42
     def reject
55 43
       authorize @account.user, :reject?
56
-      SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
44
+      SuspendAccountService.new.call(@account, reserve_email: false, reserve_username: false)
57 45
       redirect_to admin_pending_accounts_path
58 46
     end
59 47
 

+ 34
- 68
app/controllers/admin/custom_emojis_controller.rb View File

@@ -2,19 +2,20 @@
2 2
 
3 3
 module Admin
4 4
   class CustomEmojisController < BaseController
5
-    before_action :set_custom_emoji, except: [:index, :new, :create]
6
-    before_action :set_filter_params
7
-
8 5
     include ObfuscateFilename
6
+
9 7
     obfuscate_filename [:custom_emoji, :image]
10 8
 
11 9
     def index
12 10
       authorize :custom_emoji, :index?
11
+
13 12
       @custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
13
+      @form          = Form::CustomEmojiBatch.new
14 14
     end
15 15
 
16 16
     def new
17 17
       authorize :custom_emoji, :create?
18
+
18 19
       @custom_emoji = CustomEmoji.new
19 20
     end
20 21
 
@@ -31,69 +32,17 @@ module Admin
31 32
       end
32 33
     end
33 34
 
34
-    def update
35
-      authorize @custom_emoji, :update?
36
-
37
-      if @custom_emoji.update(resource_params)
38
-        log_action :update, @custom_emoji
39
-        flash[:notice] = I18n.t('admin.custom_emojis.updated_msg')
40
-      else
41
-        flash[:alert] =  I18n.t('admin.custom_emojis.update_failed_msg')
42
-      end
43
-      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
44
-    end
45
-
46
-    def destroy
47
-      authorize @custom_emoji, :destroy?
48
-      @custom_emoji.destroy!
49
-      log_action :destroy, @custom_emoji
50
-      flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg')
51
-      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
52
-    end
53
-
54
-    def copy
55
-      authorize @custom_emoji, :copy?
56
-
57
-      emoji = CustomEmoji.find_or_initialize_by(domain: nil,
58
-                                                shortcode: @custom_emoji.shortcode)
59
-      emoji.image = @custom_emoji.image
60
-
61
-      if emoji.save
62
-        log_action :create, emoji
63
-        flash[:notice] = I18n.t('admin.custom_emojis.copied_msg')
64
-      else
65
-        flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
66
-      end
67
-
68
-      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
69
-    end
70
-
71
-    def enable
72
-      authorize @custom_emoji, :enable?
73
-      @custom_emoji.update!(disabled: false)
74
-      log_action :enable, @custom_emoji
75
-      flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg')
76
-      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
77
-    end
78
-
79
-    def disable
80
-      authorize @custom_emoji, :disable?
81
-      @custom_emoji.update!(disabled: true)
82
-      log_action :disable, @custom_emoji
83
-      flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg')
84
-      redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
35
+    def batch
36
+      @form = Form::CustomEmojiBatch.new(form_custom_emoji_batch_params.merge(current_account: current_account, action: action_from_button))
37
+      @form.save
38
+    rescue ActionController::ParameterMissing
39
+      flash[:alert] = I18n.t('admin.accounts.no_account_selected')
40
+    ensure
41
+      redirect_to admin_custom_emojis_path(filter_params)
85 42
     end
86 43
 
87 44
     private
88 45
 
89
-    def set_custom_emoji
90
-      @custom_emoji = CustomEmoji.find(params[:id])
91
-    end
92
-
93
-    def set_filter_params
94
-      @filter_params = filter_params.to_hash.symbolize_keys
95
-    end
96
-
97 46
     def resource_params
98 47
       params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
99 48
     end
@@ -103,12 +52,29 @@ module Admin
103 52
     end
104 53
 
105 54
     def filter_params
106
-      params.permit(
107
-        :local,
108
-        :remote,
109
-        :by_domain,
110
-        :shortcode
111
-      )
55
+      params.slice(:local, :remote, :by_domain, :shortcode, :page).permit(:local, :remote, :by_domain, :shortcode, :page)
56
+    end
57
+
58
+    def action_from_button
59
+      if params[:update]
60
+        'update'
61
+      elsif params[:list]
62
+        'list'
63
+      elsif params[:unlist]
64
+        'unlist'
65
+      elsif params[:enable]
66
+        'enable'
67
+      elsif params[:disable]
68
+        'disable'
69
+      elsif params[:copy]
70
+        'copy'
71
+      elsif params[:delete]
72
+        'delete'
73
+      end
74
+    end
75
+
76
+    def form_custom_emoji_batch_params
77
+      params.require(:form_custom_emoji_batch).permit(:action, :category_id, :category_name, custom_emoji_ids: [])
112 78
     end
113 79
   end
114 80
 end

+ 15
- 3
app/controllers/admin/dashboard_controller.rb View File

@@ -5,6 +5,7 @@ module Admin
5 5
   class DashboardController < BaseController
6 6
     def index
7 7
       @users_count           = User.count
8
+      @pending_users_count   = User.pending.count
8 9
       @registrations_week    = Redis.current.get("activity:accounts:local:#{current_week}") || 0
9 10
       @logins_week           = Redis.current.pfcount("activity:logins:#{current_week}")
10 11
       @interactions_week     = Redis.current.get("activity:interactions:#{current_week}") || 0
@@ -19,7 +20,7 @@ module Admin
19 20
       @redis_version         = redis_info['redis_version']
20 21
       @reports_count         = Report.unresolved.count
21 22
       @queue_backlog         = Sidekiq::Stats.new.enqueued
22
-      @recent_users          = User.confirmed.recent.includes(:account).limit(4)
23
+      @recent_users          = User.confirmed.recent.includes(:account).limit(8)
23 24
       @database_size         = ActiveRecord::Base.connection.execute('SELECT pg_database_size(current_database())').first['pg_database_size']
24 25
       @redis_size            = redis_info['used_memory']
25 26
       @ldap_enabled          = ENV['LDAP_ENABLED'] == 'true'
@@ -27,9 +28,14 @@ module Admin
27 28
       @saml_enabled          = ENV['SAML_ENABLED'] == 'true'
28 29
       @pam_enabled           = ENV['PAM_ENABLED'] == 'true'
29 30
       @hidden_service        = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'
30
-      @trending_hashtags     = TrendingTags.get(7)
31
+      @trending_hashtags     = TrendingTags.get(10, filtered: false)
32
+      @pending_tags_count    = Tag.pending_review.count
33
+      @authorized_fetch      = authorized_fetch_mode?
34
+      @whitelist_enabled     = whitelist_mode?
31 35
       @profile_directory     = Setting.profile_directory
32 36
       @timeline_preview      = Setting.timeline_preview
37
+      @spam_check_enabled    = Setting.spam_check_enabled
38
+      @trends_enabled        = Setting.trends
33 39
     end
34 40
 
35 41
     private
@@ -39,7 +45,13 @@ module Admin
39 45
     end
40 46
 
41 47
     def redis_info
42
-      @redis_info ||= Redis.current.info
48
+      @redis_info ||= begin
49
+        if Redis.current.is_a?(Redis::Namespace)
50
+          Redis.current.redis.info
51
+        else
52
+          Redis.current.info
53
+        end
54
+      end
43 55
     end
44 56
   end
45 57
 end

+ 40
- 0
app/controllers/admin/domain_allows_controller.rb View File

@@ -0,0 +1,40 @@
1
+# frozen_string_literal: true
2
+
3
+class Admin::DomainAllowsController < Admin::BaseController
4
+  before_action :set_domain_allow, only: [:destroy]
5
+
6
+  def new
7
+    authorize :domain_allow, :create?
8
+
9
+    @domain_allow = DomainAllow.new(domain: params[:_domain])
10
+  end
11
+
12
+  def create
13
+    authorize :domain_allow, :create?
14
+
15
+    @domain_allow = DomainAllow.new(resource_params)
16
+
17
+    if @domain_allow.save
18
+      log_action :create, @domain_allow
19
+      redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.created_msg')
20
+    else
21
+      render :new
22
+    end
23
+  end
24
+
25
+  def destroy
26
+    authorize @domain_allow, :destroy?
27
+    UnallowDomainService.new.call(@domain_allow)
28
+    redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg')
29
+  end
30
+
31
+  private
32
+
33
+  def set_domain_allow
34
+    @domain_allow = DomainAllow.find(params[:id])
35
+  end
36
+
37
+  def resource_params
38
+    params.require(:domain_allow).permit(:domain)
39
+  end
40
+end

+ 26
- 2
app/controllers/admin/domain_blocks_controller.rb View File

@@ -2,13 +2,17 @@
2 2
 
3 3
 module Admin
4 4
   class DomainBlocksController < BaseController
5
-    before_action :set_domain_block, only: [:show, :destroy]
5
+    before_action :set_domain_block, only: [:show, :destroy, :edit, :update]
6 6
 
7 7
     def new
8 8
       authorize :domain_block, :create?
9 9
       @domain_block = DomainBlock.new(domain: params[:_domain])
10 10
     end
11 11
 
12
+    def edit
13
+      authorize :domain_block, :create?
14
+    end
15
+
12 16
     def create
13 17
       authorize :domain_block, :create?
14 18
 
@@ -35,6 +39,22 @@ module Admin
35 39
       end
36 40
     end
37 41
 
42
+    def update
43
+      authorize :domain_block, :create?
44
+
45
+      @domain_block.update(update_params)
46
+
47
+      severity_changed = @domain_block.severity_changed?
48
+
49
+      if @domain_block.save
50
+        DomainBlockWorker.perform_async(@domain_block.id, severity_changed)
51
+        log_action :create, @domain_block
52
+        redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
53
+      else
54
+        render :edit
55
+      end
56
+    end
57
+
38 58
     def show
39 59
       authorize @domain_block, :show?
40 60
     end
@@ -52,8 +72,12 @@ module Admin
52 72
       @domain_block = DomainBlock.find(params[:id])
53 73
     end
54 74
 
75
+    def update_params
76
+      params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment)
77
+    end
78
+
55 79
     def resource_params
56
-      params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)
80
+      params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment)
57 81
     end
58 82
   end
59 83
 end

+ 27
- 3
app/controllers/admin/instances_controller.rb View File

@@ -2,6 +2,10 @@
2 2
 
3 3
 module Admin
4 4
   class InstancesController < BaseController
5
+    before_action :set_domain_block, only: :show
6
+    before_action :set_domain_allow, only: :show
7
+    before_action :set_instance, only: :show
8
+
5 9
     def index
6 10
       authorize :instance, :index?
7 11
 
@@ -11,20 +15,40 @@ module Admin
11 15
     def show
12 16
       authorize :instance, :show?
13 17
 
14
-      @instance        = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id]))
15 18
       @following_count = Follow.where(account: Account.where(domain: params[:id])).count
16 19
       @followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count
17 20
       @reports_count   = Report.where(target_account: Account.where(domain: params[:id])).count
18 21
       @blocks_count    = Block.where(target_account: Account.where(domain: params[:id])).count
19 22
       @available       = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url)
20 23
       @media_storage   = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)
21
-      @domain_block    = DomainBlock.rule_for(params[:id])
24
+      @private_comment = @domain_block&.private_comment
25
+      @public_comment  = @domain_block&.public_comment
22 26
     end
23 27
 
24 28
     private
25 29
 
30
+    def set_domain_block
31
+      @domain_block = DomainBlock.rule_for(params[:id])
32
+    end
33
+
34
+    def set_domain_allow
35
+      @domain_allow = DomainAllow.rule_for(params[:id])
36
+    end
37
+
38
+    def set_instance
39
+      resource   = Account.by_domain_accounts.find_by(domain: params[:id])
40
+      resource ||= @domain_block
41
+      resource ||= @domain_allow
42
+
43
+      if resource
44
+        @instance = Instance.new(resource)
45
+      else
46
+        not_found
47
+      end
48
+    end
49
+
26 50
     def filtered_instances
27
-      InstanceFilter.new(filter_params).results
51
+      InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
28 52
     end
29 53
 
30 54
     def paginated_instances

+ 6
- 1
app/controllers/admin/relays_controller.rb View File