diff --git a/.circleci/config.yml b/.circleci/config.yml
index 674d1b02d..1161e4076 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -13,8 +13,8 @@ aliases:
ALLOW_NOPAM: true
CONTINUOUS_INTEGRATION: true
DISABLE_SIMPLECOV: true
- PAM_ENABLED: true
- PAM_DEFAULT_SERVICE: pam_test
+ PAM_ENABLED: true
+ PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
working_directory: ~/projects/mastodon/
@@ -175,6 +175,8 @@ jobs:
- *attach_workspace
- run: bundle exec i18n-tasks check-normalized
- run: bundle exec i18n-tasks unused
+ - run: bundle exec i18n-tasks missing -t plural
+ - run: bundle exec i18n-tasks check-consistent-interpolations
workflows:
version: 2
diff --git a/AUTHORS.md b/AUTHORS.md
index 277683a00..b81b6d245 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -25,16 +25,16 @@ and provided thanks to the work of the following contributors:
* [JantsoP](https://github.com/JantsoP)
* [nullkal](https://github.com/nullkal)
* [yookoala](https://github.com/yookoala)
+* [mabkenar](https://github.com/mabkenar)
* [ysksn](https://github.com/ysksn)
* [shuheiktgw](https://github.com/shuheiktgw)
* [ashfurrow](https://github.com/ashfurrow)
-* [mabkenar](https://github.com/mabkenar)
-* [zunda](https://github.com/zunda)
* [Kjwon15](https://github.com/Kjwon15)
+* [zunda](https://github.com/zunda)
* [eramdam](https://github.com/eramdam)
* [masarakki](https://github.com/masarakki)
-* [ticky](https://github.com/ticky)
* [takayamaki](https://github.com/takayamaki)
+* [ticky](https://github.com/ticky)
* [Quenty31](https://github.com/Quenty31)
* [danhunsaker](https://github.com/danhunsaker)
* [ThisIsMissEm](https://github.com/ThisIsMissEm)
@@ -105,6 +105,7 @@ and provided thanks to the work of the following contributors:
* [ProgVal](https://github.com/ProgVal)
* [valentin2105](https://github.com/valentin2105)
* [yuntan](https://github.com/yuntan)
+* [ashleyhull-versent](https://github.com/ashleyhull-versent)
* [goofy-bz](mailto:goofy@babelzilla.org)
* [kadiix](https://github.com/kadiix)
* [kodacs](https://github.com/kodacs)
@@ -127,9 +128,9 @@ and provided thanks to the work of the following contributors:
* [reneklacan](https://github.com/reneklacan)
* [ekiru](https://github.com/ekiru)
* [tcitworld](https://github.com/tcitworld)
-* [ashleyhull-versent](https://github.com/ashleyhull-versent)
* [geta6](https://github.com/geta6)
* [happycoloredbanana](https://github.com/happycoloredbanana)
+* [kedamaDQ](https://github.com/kedamaDQ)
* [leopku](https://github.com/leopku)
* [SansPseudoFix](https://github.com/SansPseudoFix)
* [tomfhowe](https://github.com/tomfhowe)
@@ -146,7 +147,7 @@ and provided thanks to the work of the following contributors:
* [treby](https://github.com/treby)
* [Reverite](https://github.com/Reverite)
* [jpdevries](https://github.com/jpdevries)
-* [00x9d](https://github.com/00x9d)
+* [H-C-F](https://github.com/H-C-F)
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
* [saper](https://github.com/saper)
* [nevillepark](https://github.com/nevillepark)
@@ -195,6 +196,7 @@ and provided thanks to the work of the following contributors:
* [Fjoerfoks](https://github.com/Fjoerfoks)
* [fmauNeko](https://github.com/fmauNeko)
* [gloaec](https://github.com/gloaec)
+* [Gomasy](https://github.com/Gomasy)
* [unstabler](https://github.com/unstabler)
* [potato4d](https://github.com/potato4d)
* [h-izumi](https://github.com/h-izumi)
@@ -221,6 +223,7 @@ and provided thanks to the work of the following contributors:
* [petzah](https://github.com/petzah)
* [ignisf](https://github.com/ignisf)
* [raymestalez](https://github.com/raymestalez)
+* [sascha-sl](https://github.com/sascha-sl)
* [u1-liquid](https://github.com/u1-liquid)
* [sim6](https://github.com/sim6)
* [stemid](https://github.com/stemid)
@@ -248,7 +251,6 @@ and provided thanks to the work of the following contributors:
* [haoyayoi](https://github.com/haoyayoi)
* [ik11235](https://github.com/ik11235)
* [kawax](https://github.com/kawax)
-* [kedamaDQ](https://github.com/kedamaDQ)
* [007lva](https://github.com/007lva)
* [matsurai25](https://github.com/matsurai25)
* [mecab](https://github.com/mecab)
@@ -274,6 +276,7 @@ and provided thanks to the work of the following contributors:
* [Aditoo17](https://github.com/Aditoo17)
* [unascribed](https://github.com/unascribed)
* [Aguay-val](https://github.com/Aguay-val)
+* [Akihiko Odaki](mailto:nekomanma@pixiv.co.jp)
* [knu](https://github.com/knu)
* [h3poteto](https://github.com/h3poteto)
* [unleashed](https://github.com/unleashed)
@@ -296,6 +299,7 @@ and provided thanks to the work of the following contributors:
* [ayumin](https://github.com/ayumin)
* [BaptisteGelez](https://github.com/BaptisteGelez)
* [bzg](https://github.com/bzg)
+* [BenLubar](https://github.com/BenLubar)
* [benediktg](https://github.com/benediktg)
* [blakebarnett](https://github.com/blakebarnett)
* [bradj](https://github.com/bradj)
@@ -341,7 +345,6 @@ and provided thanks to the work of the following contributors:
* [hattori6789](https://github.com/hattori6789)
* [algernon](https://github.com/algernon)
* [Fastbyte01](https://github.com/Fastbyte01)
-* [Gomasy](https://github.com/Gomasy)
* [myfreeweb](https://github.com/myfreeweb)
* [gfaivre](https://github.com/gfaivre)
* [Fiaxhs](https://github.com/Fiaxhs)
@@ -365,7 +368,7 @@ and provided thanks to the work of the following contributors:
* [Floppy](https://github.com/Floppy)
* [loomchild](https://github.com/loomchild)
* [jenkr55](https://github.com/jenkr55)
-* [docjkl](https://github.com/docjkl)
+* [press5](https://github.com/press5)
* [TrollDecker](https://github.com/TrollDecker)
* [jmontane](https://github.com/jmontane)
* [jonathanklee](https://github.com/jonathanklee)
@@ -450,7 +453,6 @@ and provided thanks to the work of the following contributors:
* [staticsafe](https://github.com/staticsafe)
* [snwh](https://github.com/snwh)
* [sts10](https://github.com/sts10)
-* [sascha-sl](https://github.com/sascha-sl)
* [skoji](https://github.com/skoji)
* [ScienJus](https://github.com/ScienJus)
* [larkinscott](https://github.com/larkinscott)
@@ -464,7 +466,7 @@ and provided thanks to the work of the following contributors:
* [shouko](https://github.com/shouko)
* [Sina Mashek](mailto:sina@mashek.xyz)
* [sossii](https://github.com/sossii)
-* [SpankyWorks](https://github.com/SpankyWorks)
+* [Spanky](mailto:2788886+spankyworks@users.noreply.github.com)
* [StefOfficiel](mailto:pichard.stephane@free.fr)
* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com)
* [Sébastien Santoro](mailto:dereckson@espace-win.org)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 666ccd14b..1e24df451 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,14 +3,87 @@ Changelog
All notable changes to this project will be documented in this file.
-## [Unreleased]
+## [2.6.5] - 2018-12-01
+### Changed
+
+- Change lists to display replies to others on the list and list owner (#9324)
+
+### Fixed
+
+- Fix failures caused by commonly-used JSON-LD contexts being unavailable (#9412)
+
+## [2.6.4] - 2018-11-30
+### Fixed
+
+- Fix yarn dependencies not installing due to yanked event-stream package (#9401)
+
+## [2.6.3] - 2018-11-30
+### Added
+
+- Add hyphen to characters allowed in remote usernames (#9345)
+
+### Changed
+
+- Change server user count to exclude suspended accounts (#9380)
+
+### Fixed
+
+- Fix ffmpeg processing sometimes stalling due to overfilled stdout buffer (#9368)
+- Fix missing DNS records raising the wrong kind of exception (#9379)
+- Fix already queued deliveries still trying to reach inboxes marked as unavailable (#9358)
+
+### Security
+
+- Fix TLS handshake timeout not being enforced (#9381)
+
+## [2.6.2] - 2018-11-23
+### Added
+
+- Add Page to whitelisted ActivityPub types (#9188)
+- Add 20px to column width in web UI (#9227)
+- Add amount of freed disk space in `tootctl media remove` (#9229, #9239, #9288)
+- Add "Show thread" link to self-replies (#9228)
+
+### Changed
+
+- Change order of Atom and RSS links so Atom is first (#9302)
+- Change Nginx configuration for Nanobox apps (#9310)
+- Change the follow action to appear instant in web UI (#9220)
+- Change how the ActiveRecord connection is instantiated in on_worker_boot (#9238)
+- Change `tootctl accounts cull` to always touch accounts so they can be skipped (#9293)
+- Change mime type comparison to ignore JSON-LD profile (#9179)
+
+### Fixed
+
+- Fix web UI crash when conversation has no last status (#9207)
+- Fix follow limit validator reporting lower number past threshold (#9230)
+- Fix form validation flash message color and input borders (#9235)
+- Fix invalid twitter:player cards being displayed (#9254)
+- Fix emoji update date being processed incorrectly (#9255)
+- Fix playing embed resetting if status is reloaded in web UI (#9270, #9275)
+- Fix web UI crash when favouriting a deleted status (#9272)
+- Fix intermediary arrays being created for hash maps (#9291)
+- Fix filter ID not being a string in REST API (#9303)
+
+### Security
+
+- Fix multiple remote account deletions being able to deadlock the database (#9292)
+- Fix HTTP connection timeout of 10s not being enforced (#9329)
+
+## [2.6.1] - 2018-10-30
+### Fixed
+
+- Fix resolving resources by URL not working due to a regression in #9132 (#9171)
+- Fix reducer error in web UI when a conversation has no last status (#9173)
+
+## [2.6.0] - 2018-10-30
### Added
- Add link ownership verification (#8703)
- Add conversations API (#8832)
- Add limit for the number of people that can be followed from one account (#8807)
- Add admin setting to customize mascot (#8766)
-- Add support for more granular ActivityPub audiences from other software, i.e. circles (#8950)
+- Add support for more granular ActivityPub audiences from other software, i.e. circles (#8950, #9093, #9150)
- Add option to block all reports from a domain (#8830)
- Add user preference to always expand toots marked with content warnings (#8762)
- Add user preference to always hide all media (#8569)
@@ -30,7 +103,6 @@ All notable changes to this project will be documented in this file.
- Add PostgreSQL disk space growth tracking in PGHero (#8906)
- Add button for disabling local account to report quick actions bar (#9024)
- Add Czech language (#8594)
-- Add `Clear-Site-Data` header when logging out (#8627)
- Add `same-site` (`lax`) attribute to cookies (#8626)
- Add support for styled scrollbars in Firefox Nightly (#8653)
- Add highlight to the active tab in web UI profiles (#8673)
@@ -43,6 +115,11 @@ All notable changes to this project will be documented in this file.
- Add `description` meta tag (#8941)
- Add `Content-Security-Policy` header (#8957)
- Add cache for the instance info API (#8765)
+- Add suggested follows to search screen in mobile layout (#9010)
+- Add CORS header to `/.well-known/*` routes (#9083)
+- Add `card` attribute to statuses returned from REST API (#9120)
+- Add in-stream link preview (#9120)
+- Add support for ActivityPub `Page` objects (#9121)
### Changed
@@ -57,11 +134,17 @@ All notable changes to this project will be documented in this file.
- Change style of success and failure messages (#8973)
- Change DM filtering to always allow DMs from staff (#8993)
- Change recommended Ruby version to 2.5.3 (#9003)
+- Change docker-compose default to persist volumes in current directory (#9055)
+- Change character counters on edit profile page to input length limit (#9100)
+- Change notification filtering to always let through messages from staff (#9152)
+- Change "hide boosts from user" function also hiding notifications about boosts (#9147)
+- Change CSS `detailed-status__wrapper` class actually wrap the detailed status (#8547)
### Deprecated
- `GET /api/v1/timelines/direct` → `GET /api/v1/conversations` (#8832)
- `POST /api/v1/notifications/dismiss` → `POST /api/v1/notifications/:id/dismiss` (#8905)
+- `GET /api/v1/statuses/:id/card` → `card` attributed included in status (#9120)
### Removed
@@ -81,10 +164,21 @@ All notable changes to this project will be documented in this file.
- Fix some dark emojis not having a white outline (#8597)
- Fix media description not being displayed in various media modals (#8678)
- Fix generated URLs of desktop notifications missing base URL (#8758)
-- Fix RTL styles (#8764, #8767, #8823, #8897, #9005, #9007, #9018, #9021)
+- Fix RTL styles (#8764, #8767, #8823, #8897, #9005, #9007, #9018, #9021, #9145, #9146)
- Fix crash in streaming API when tag param missing (#8955)
- Fix hotkeys not working when no element is focused (#8998)
- Fix some hotkeys not working on detailed status view (#9006)
+- Fix og:url on status pages (#9047)
+- Fix upload option buttons only being visible on hover (#9074)
+- Fix tootctl not returning exit code 1 on wrong arguments (#9094)
+- Fix preview cards for appearing for profiles mentioned in toot (#6934, #9158)
+- Fix local accounts sometimes being duplicated as faux-remote (#9109)
+- Fix emoji search when the shortcode has multiple separators (#9124)
+- Fix dropdowns sometimes being partially obscured by other elements (#9126)
+- Fix cache not updating when reply/boost/favourite counters or media sensitivity update (#9119)
+- Fix empty display name precedence over username in web UI (#9163)
+- Fix td instead of th in sessions table header (#9162)
+- Fix handling of content types with profile (#9132)
## [2.5.2] - 2018-10-12
### Security
diff --git a/Dockerfile b/Dockerfile
index 6a1e8776c..9c53b4145 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
FROM node:8.12.0-alpine as node
-FROM ruby:2.4.4-alpine3.7
+FROM ruby:2.4.5-alpine3.8
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="Your self-hosted, globally interconnected microblogging community"
diff --git a/Gemfile b/Gemfile
index c5e825335..6e1c9403a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,9 +15,9 @@ gem 'makara', '~> 0.4'
gem 'pghero', '~> 2.2'
gem 'dotenv-rails', '~> 2.5'
-gem 'aws-sdk-s3', '~> 1.21', require: false
-gem 'fog-core', '~> 2.1'
-gem 'fog-openstack', '~> 1.0', require: false
+gem 'aws-sdk-s3', '~> 1.23', require: false
+gem 'fog-core', '<= 2.1.0'
+gem 'fog-openstack', '~> 0.3', require: false
gem 'paperclip', '~> 6.0'
gem 'paperclip-av-transcoder', '~> 0.6'
gem 'streamio-ffmpeg', '~> 3.0'
@@ -59,7 +59,7 @@ gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.2', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.8'
gem 'nsa', '~> 0.2'
-gem 'oj', '~> 3.6'
+gem 'oj', '~> 3.7'
gem 'ostatus2', '~> 2.0'
gem 'ox', '~> 2.10'
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
@@ -72,7 +72,7 @@ gem 'rails-settings-cached', '~> 0.6'
gem 'redis', '~> 4.0', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10'
-gem 'sanitize', '~> 4.6'
+gem 'sanitize', '~> 5.0'
gem 'sidekiq', '~> 5.2'
gem 'sidekiq-scheduler', '~> 3.0'
gem 'sidekiq-unique-jobs', '~> 5.0'
@@ -90,6 +90,7 @@ gem 'webpacker', '~> 3.5'
gem 'webpush'
gem 'json-ld', '~> 2.2'
+gem 'json-ld-preloaded', '~> 2.2'
gem 'rdf-normalize', '~> 0.3'
group :development, :test do
@@ -106,7 +107,7 @@ group :production, :test do
end
group :test do
- gem 'capybara', '~> 3.9'
+ gem 'capybara', '~> 3.10'
gem 'climate_control', '~> 0.2'
gem 'faker', '~> 1.9'
gem 'microformats', '~> 4.0'
@@ -114,7 +115,7 @@ group :test do
gem 'rspec-sidekiq', '~> 3.0'
gem 'simplecov', '~> 0.16', require: false
gem 'webmock', '~> 3.4'
- gem 'parallel_tests', '~> 2.23'
+ gem 'parallel_tests', '~> 2.26'
end
group :development do
@@ -126,7 +127,7 @@ group :development do
gem 'letter_opener', '~> 1.4'
gem 'letter_opener_web', '~> 1.3'
gem 'memory_profiler'
- gem 'rubocop', '~> 0.59', require: false
+ gem 'rubocop', '~> 0.60', require: false
gem 'brakeman', '~> 4.3', require: false
gem 'bundler-audit', '~> 0.6', require: false
gem 'scss_lint', '~> 0.57', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index fa36d4cbe..d83ad6d8b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -76,16 +76,16 @@ GEM
av (0.9.0)
cocaine (~> 0.5.3)
aws-eventstream (1.0.1)
- aws-partitions (1.105.0)
- aws-sdk-core (3.30.0)
+ aws-partitions (1.106.0)
+ aws-sdk-core (3.35.0)
aws-eventstream (~> 1.0)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
- aws-sdk-kms (1.9.0)
+ aws-sdk-kms (1.11.0)
aws-sdk-core (~> 3, >= 3.26.0)
aws-sigv4 (~> 1.0)
- aws-sdk-s3 (1.21.0)
+ aws-sdk-s3 (1.23.0)
aws-sdk-core (~> 3, >= 3.26.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0)
@@ -126,13 +126,14 @@ GEM
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
- capybara (3.9.0)
+ capybara (3.10.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
- xpath (~> 3.1)
+ regexp_parser (~> 1.2)
+ xpath (~> 3.2)
case_transform (0.2)
activesupport
charlock_holmes (0.7.6)
@@ -182,7 +183,7 @@ GEM
docile (1.3.0)
domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0)
- doorkeeper (5.0.1)
+ doorkeeper (5.0.2)
railties (>= 4.2)
dotenv (2.5.0)
dotenv-rails (2.5.0)
@@ -211,7 +212,7 @@ GEM
fast_blank (1.0.0)
fastimage (2.1.4)
ffi (1.9.25)
- fog-core (2.1.2)
+ fog-core (2.1.0)
builder
excon (~> 0.58)
formatador (~> 0.2)
@@ -219,8 +220,8 @@ GEM
fog-json (1.2.0)
fog-core
multi_json (~> 1.10)
- fog-openstack (1.0.3)
- fog-core (~> 2.1)
+ fog-openstack (0.3.7)
+ fog-core (>= 1.45, <= 2.1.0)
fog-json (>= 1.0)
ipaddress (>= 0.8)
formatador (0.2.5)
@@ -271,13 +272,14 @@ GEM
rainbow (>= 2.0.0)
i18n (1.1.1)
concurrent-ruby (~> 1.0)
- i18n-tasks (0.9.25)
+ i18n-tasks (0.9.28)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
erubi
highline (>= 2.0.0)
i18n
parser (>= 2.2.3.0)
+ rails-i18n
rainbow (>= 2.2.2, < 4.0)
terminal-table (>= 1.5.1)
idn-ruby (0.1.0)
@@ -289,6 +291,10 @@ GEM
json-ld (2.2.1)
multi_json (~> 1.12)
rdf (>= 2.2.8, < 4.0)
+ json-ld-preloaded (2.2.3)
+ json-ld (>= 2.2, < 4.0)
+ multi_json (~> 1.12)
+ rdf (>= 2.2, < 4.0)
jsonapi-renderer (0.2.0)
jwt (2.1.0)
kaminari (1.1.1)
@@ -317,7 +323,7 @@ GEM
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
- loofah (2.2.2)
+ loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
@@ -351,14 +357,14 @@ GEM
nio4r (2.3.1)
nokogiri (1.8.5)
mini_portile2 (~> 2.3.0)
- nokogumbo (1.5.0)
- nokogiri
+ nokogumbo (2.0.0)
+ nokogiri (~> 1.8, >= 1.8.4)
nsa (0.2.4)
activesupport (>= 4.2, < 6)
concurrent-ruby (~> 1.0.0)
sidekiq (>= 3.5.0)
statsd-ruby (~> 1.2.0)
- oj (3.6.12)
+ oj (3.7.0)
omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
@@ -385,9 +391,9 @@ GEM
av (~> 0.9.0)
paperclip (>= 2.5.2)
parallel (1.12.1)
- parallel_tests (2.23.0)
+ parallel_tests (2.26.0)
parallel
- parser (2.5.1.2)
+ parser (2.5.3.0)
ast (~> 2.4.0)
pastel (0.7.2)
equatable (~> 0.5.0)
@@ -450,7 +456,7 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
- rails-i18n (5.1.1)
+ rails-i18n (5.1.2)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
rails-settings-cached (0.6.6)
@@ -490,6 +496,7 @@ GEM
redis-store (>= 1.2, < 2)
redis-store (1.5.0)
redis (>= 2.2, < 5)
+ regexp_parser (1.2.0)
request_store (1.4.1)
rack (>= 1.4)
responders (2.4.0)
@@ -501,13 +508,13 @@ GEM
chunky_png (~> 1.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
- rspec-expectations (3.8.1)
+ rspec-expectations (3.8.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
- rspec-rails (3.8.0)
+ rspec-rails (3.8.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@@ -519,24 +526,24 @@ GEM
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.8.0)
- rubocop (0.59.2)
+ rubocop (0.60.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
- unicode-display_width (~> 1.0, >= 1.0.1)
- ruby-progressbar (1.9.0)
+ unicode-display_width (~> 1.4.0)
+ ruby-progressbar (1.10.0)
ruby-saml (1.9.0)
nokogiri (>= 1.5.10)
rufus-scheduler (3.5.2)
fugit (~> 1.1, >= 1.1.5)
safe_yaml (1.0.4)
- sanitize (4.6.6)
+ sanitize (5.0.0)
crass (~> 1.0.2)
- nokogiri (>= 1.4.4)
- nokogumbo (~> 1.4)
+ nokogiri (>= 1.8.0)
+ nokogumbo (~> 2.0)
sass (3.6.0)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
@@ -616,7 +623,7 @@ GEM
unf (~> 0.1.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
- tzinfo-data (1.2018.6)
+ tzinfo-data (1.2018.7)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@@ -640,7 +647,7 @@ GEM
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
wisper (2.0.0)
- xpath (3.1.0)
+ xpath (3.2.0)
nokogiri (~> 1.8)
PLATFORMS
@@ -651,7 +658,7 @@ DEPENDENCIES
active_record_query_trace (~> 1.5)
addressable (~> 2.5)
annotate (~> 2.7)
- aws-sdk-s3 (~> 1.21)
+ aws-sdk-s3 (~> 1.23)
better_errors (~> 2.5)
binding_of_caller (~> 0.7)
bootsnap (~> 1.3)
@@ -663,7 +670,7 @@ DEPENDENCIES
capistrano-rails (~> 1.4)
capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0)
- capybara (~> 3.9)
+ capybara (~> 3.10)
charlock_holmes (~> 0.7.6)
chewy (~> 5.0)
cld3 (~> 3.2.0)
@@ -678,8 +685,8 @@ DEPENDENCIES
faker (~> 1.9)
fast_blank (~> 1.0)
fastimage
- fog-core (~> 2.1)
- fog-openstack (~> 1.0)
+ fog-core (<= 2.1.0)
+ fog-openstack (~> 0.3)
fuubar (~> 2.3)
goldfinger (~> 2.1)
hamlit-rails (~> 0.2)
@@ -693,6 +700,7 @@ DEPENDENCIES
idn-ruby
iso-639
json-ld (~> 2.2)
+ json-ld-preloaded (~> 2.2)
kaminari (~> 1.1)
letter_opener (~> 1.4)
letter_opener_web (~> 1.3)
@@ -706,7 +714,7 @@ DEPENDENCIES
net-ldap (~> 0.10)
nokogiri (~> 1.8)
nsa (~> 0.2)
- oj (~> 3.6)
+ oj (~> 3.7)
omniauth (~> 1.2)
omniauth-cas (~> 1.1)
omniauth-saml (~> 1.10)
@@ -714,7 +722,7 @@ DEPENDENCIES
ox (~> 2.10)
paperclip (~> 6.0)
paperclip-av-transcoder (~> 0.6)
- parallel_tests (~> 2.23)
+ parallel_tests (~> 2.26)
pg (~> 1.1)
pghero (~> 2.2)
pkg-config (~> 1.3)
@@ -738,8 +746,8 @@ DEPENDENCIES
rqrcode (~> 0.10)
rspec-rails (~> 3.8)
rspec-sidekiq (~> 3.0)
- rubocop (~> 0.59)
- sanitize (~> 4.6)
+ rubocop (~> 0.60)
+ sanitize (~> 5.0)
scss_lint (~> 0.57)
sidekiq (~> 5.2)
sidekiq-bulk (~> 0.1.1)
@@ -766,4 +774,4 @@ RUBY VERSION
ruby 2.5.3p105
BUNDLED WITH
- 1.16.5
+ 1.16.6
diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb
index af51e32d5..8f5e1887e 100644
--- a/app/controllers/activitypub/inboxes_controller.rb
+++ b/app/controllers/activitypub/inboxes_controller.rb
@@ -36,6 +36,6 @@ class ActivityPub::InboxesController < Api::BaseController
end
def process_payload
- ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body.force_encoding('UTF-8'))
+ ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body.force_encoding('UTF-8'), @account&.id)
end
end
diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb
index 7fb69d578..8593b582a 100644
--- a/app/controllers/admin/base_controller.rb
+++ b/app/controllers/admin/base_controller.rb
@@ -5,8 +5,15 @@ module Admin
include Authorization
include AccountableConcern
- before_action :require_staff!
-
layout 'admin'
+
+ before_action :require_staff!
+ before_action :set_body_classes
+
+ private
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
end
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 1d5372a8c..f711c4676 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -17,7 +17,7 @@ class Api::V1::AccountsController < Api::BaseController
end
def follow
- FollowService.new.call(current_user.account, @account.acct, reblogs: truthy_param?(:reblogs))
+ FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs))
options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index fb4283da3..b54e7b008 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -113,7 +113,7 @@ class ApplicationController < ActionController::Base
klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)
unless uncached_ids.empty?
- uncached = klass.where(id: uncached_ids).with_includes.map { |item| [item.id, item] }.to_h
+ uncached = klass.where(id: uncached_ids).with_includes.each_with_object({}) { |item, h| h[item.id] = item }
uncached.each_value do |item|
Rails.cache.write(item, item)
@@ -126,6 +126,7 @@ class ApplicationController < ActionController::Base
def respond_with_error(code)
respond_to do |format|
format.any { head code }
+
format.html do
set_locale
render "errors/#{code}", layout: 'error', status: code
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index a19f4e62e..088832be3 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -8,7 +8,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :set_sessions, only: [:edit, :update]
before_action :set_instance_presenter, only: [:new, :create, :update]
- before_action :set_body_classes, only: [:new, :create]
+ before_action :set_body_classes, only: [:new, :create, :edit, :update]
def destroy
not_found
@@ -81,7 +81,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
end
def set_body_classes
- @body_classes = 'lighter'
+ @body_classes = %w(edit update).include?(action_name) ? 'admin' : 'lighter'
end
def set_invite
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index 901e82331..fb8615c31 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -10,7 +10,6 @@ class Auth::SessionsController < Devise::SessionsController
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
before_action :set_instance_presenter, only: [:new]
before_action :set_body_classes
- after_action :clear_site_data, only: [:destroy]
def new
Devise.omniauth_configs.each do |provider, config|
@@ -125,14 +124,6 @@ class Auth::SessionsController < Devise::SessionsController
paths
end
- def clear_site_data
- return if continue_after?
-
- # Should be '"*"' but that doesn't work in Chrome (neither does '"executionContexts"')
- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data
- response.headers['Clear-Site-Data'] = '"cache", "cookies", "storage"'
- end
-
def continue_after?
truthy_param?(:continue)
end
diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb
index 175dbab07..d2e0fb739 100644
--- a/app/controllers/filters_controller.rb
+++ b/app/controllers/filters_controller.rb
@@ -7,6 +7,7 @@ class FiltersController < ApplicationController
before_action :set_filters, only: :index
before_action :set_filter, only: [:edit, :update, :destroy]
+ before_action :set_body_classes
def index
@filters = current_account.custom_filters
@@ -54,4 +55,8 @@ class FiltersController < ApplicationController
def resource_params
params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 3aaa2776f..fdb3a0962 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -6,6 +6,7 @@ class InvitesController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def index
authorize :invite, :create?
@@ -44,4 +45,8 @@ class InvitesController < ApplicationController
def resource_params
params.require(:invite).permit(:max_uses, :expires_in, :autofollow)
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb
index 2a4962311..a1a2c57fa 100644
--- a/app/controllers/settings/applications_controller.rb
+++ b/app/controllers/settings/applications_controller.rb
@@ -6,6 +6,7 @@ class Settings::ApplicationsController < ApplicationController
before_action :authenticate_user!
before_action :set_application, only: [:show, :update, :destroy, :regenerate]
before_action :prepare_scopes, only: [:create, :update]
+ before_action :set_body_classes
def index
@applications = current_user.applications.order(id: :desc).page(params[:page])
@@ -69,4 +70,8 @@ class Settings::ApplicationsController < ApplicationController
scopes = params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil)
params[:doorkeeper_application][:scopes] = scopes.join(' ') if scopes.is_a? Array
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb
index 80002b995..97f3946c8 100644
--- a/app/controllers/settings/deletes_controller.rb
+++ b/app/controllers/settings/deletes_controller.rb
@@ -5,6 +5,7 @@ class Settings::DeletesController < ApplicationController
before_action :check_enabled_deletion
before_action :authenticate_user!
+ before_action :set_body_classes
def show
@confirmation = Form::DeleteConfirmation.new
@@ -29,4 +30,8 @@ class Settings::DeletesController < ApplicationController
def delete_params
params.require(:form_delete_confirmation).permit(:password)
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb
index 869e11d3b..3a2334ef0 100644
--- a/app/controllers/settings/exports_controller.rb
+++ b/app/controllers/settings/exports_controller.rb
@@ -6,6 +6,7 @@ class Settings::ExportsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def show
@export = Export.new(current_account)
@@ -20,4 +21,10 @@ class Settings::ExportsController < ApplicationController
redirect_to settings_export_path
end
+
+ private
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/follower_domains_controller.rb b/app/controllers/settings/follower_domains_controller.rb
index a128bd136..9c39e66bb 100644
--- a/app/controllers/settings/follower_domains_controller.rb
+++ b/app/controllers/settings/follower_domains_controller.rb
@@ -4,6 +4,7 @@ class Settings::FollowerDomainsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def show
@account = current_account
@@ -25,4 +26,8 @@ class Settings::FollowerDomainsController < ApplicationController
def bulk_params
params.permit(select: [])
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/imports_controller.rb b/app/controllers/settings/imports_controller.rb
index 0db13d1ca..e9548ce62 100644
--- a/app/controllers/settings/imports_controller.rb
+++ b/app/controllers/settings/imports_controller.rb
@@ -5,6 +5,7 @@ class Settings::ImportsController < ApplicationController
before_action :authenticate_user!
before_action :set_account
+ before_action :set_body_classes
def show
@import = Import.new
@@ -31,4 +32,8 @@ class Settings::ImportsController < ApplicationController
def import_params
params.require(:import).permit(:data, :type)
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/migrations_controller.rb b/app/controllers/settings/migrations_controller.rb
index bc6436b87..bd4f9c87a 100644
--- a/app/controllers/settings/migrations_controller.rb
+++ b/app/controllers/settings/migrations_controller.rb
@@ -4,6 +4,7 @@ class Settings::MigrationsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def show
@migration = Form::Migration.new(account: current_account.moved_to_account)
@@ -31,4 +32,8 @@ class Settings::MigrationsController < ApplicationController
current_account.moved_to_account_id != @migration.account&.id &&
current_account.id != @migration.account&.id
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/notifications_controller.rb b/app/controllers/settings/notifications_controller.rb
index fe45c17b2..d0754296c 100644
--- a/app/controllers/settings/notifications_controller.rb
+++ b/app/controllers/settings/notifications_controller.rb
@@ -4,6 +4,7 @@ class Settings::NotificationsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def show; end
@@ -29,4 +30,8 @@ class Settings::NotificationsController < ApplicationController
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index a3cfe5eba..68cd7bc55 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -4,6 +4,7 @@ class Settings::PreferencesController < ApplicationController
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def show; end
@@ -52,4 +53,8 @@ class Settings::PreferencesController < ApplicationController
interactions: %i(must_be_follower must_be_following)
)
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb
index fe265c81d..5b3bfd71f 100644
--- a/app/controllers/settings/profiles_controller.rb
+++ b/app/controllers/settings/profiles_controller.rb
@@ -7,6 +7,7 @@ class Settings::ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :set_account
+ before_action :set_body_classes
obfuscate_filename [:account, :avatar]
obfuscate_filename [:account, :header]
@@ -34,4 +35,8 @@ class Settings::ProfilesController < ApplicationController
def set_account
@account = current_user.account
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/sessions_controller.rb b/app/controllers/settings/sessions_controller.rb
index 0da1b027b..74cebc07b 100644
--- a/app/controllers/settings/sessions_controller.rb
+++ b/app/controllers/settings/sessions_controller.rb
@@ -2,6 +2,7 @@
class Settings::SessionsController < ApplicationController
before_action :set_session, only: :destroy
+ before_action :set_body_classes
def destroy
@session.destroy!
@@ -14,4 +15,8 @@ class Settings::SessionsController < ApplicationController
def set_session
@session = current_user.session_activations.find(params[:id])
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
index 8d534960d..ee567c2a7 100644
--- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
@@ -7,6 +7,7 @@ module Settings
before_action :authenticate_user!
before_action :ensure_otp_secret
+ before_action :set_body_classes
def new
prepare_two_factor_form
@@ -43,6 +44,10 @@ module Settings
def ensure_otp_secret
redirect_to settings_two_factor_authentication_path unless current_user.otp_secret
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
end
end
diff --git a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
index e591e9502..bfb103620 100644
--- a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
@@ -6,6 +6,7 @@ module Settings
layout 'admin'
before_action :authenticate_user!
+ before_action :set_body_classes
def create
@recovery_codes = current_user.generate_otp_backup_codes!
@@ -13,6 +14,12 @@ module Settings
flash[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated')
render :index
end
+
+ private
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
end
end
diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb
index 863cc7351..e4d8aed41 100644
--- a/app/controllers/settings/two_factor_authentications_controller.rb
+++ b/app/controllers/settings/two_factor_authentications_controller.rb
@@ -6,6 +6,7 @@ module Settings
before_action :authenticate_user!
before_action :verify_otp_required, only: [:create]
+ before_action :set_body_classes
def show
@confirmation = Form::TwoFactorConfirmation.new
@@ -43,5 +44,9 @@ module Settings
current_user.validate_and_consume_otp!(confirmation_params[:code]) ||
current_user.invalidate_otp_backup_code!(confirmation_params[:code])
end
+
+ def set_body_classes
+ @body_classes = 'admin'
+ end
end
end
diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js
index cbae62a0f..d4a824e2c 100644
--- a/app/javascript/mastodon/actions/accounts.js
+++ b/app/javascript/mastodon/actions/accounts.js
@@ -145,12 +145,14 @@ export function fetchAccountFail(id, error) {
export function followAccount(id, reblogs = true) {
return (dispatch, getState) => {
const alreadyFollowing = getState().getIn(['relationships', id, 'following']);
- dispatch(followAccountRequest(id));
+ const locked = getState().getIn(['accounts', id, 'locked'], false);
+
+ dispatch(followAccountRequest(id, locked));
api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => {
dispatch(followAccountSuccess(response.data, alreadyFollowing));
}).catch(error => {
- dispatch(followAccountFail(error));
+ dispatch(followAccountFail(error, locked));
});
};
};
@@ -167,10 +169,12 @@ export function unfollowAccount(id) {
};
};
-export function followAccountRequest(id) {
+export function followAccountRequest(id, locked) {
return {
type: ACCOUNT_FOLLOW_REQUEST,
id,
+ locked,
+ skipLoading: true,
};
};
@@ -179,13 +183,16 @@ export function followAccountSuccess(relationship, alreadyFollowing) {
type: ACCOUNT_FOLLOW_SUCCESS,
relationship,
alreadyFollowing,
+ skipLoading: true,
};
};
-export function followAccountFail(error) {
+export function followAccountFail(error, locked) {
return {
type: ACCOUNT_FOLLOW_FAIL,
error,
+ locked,
+ skipLoading: true,
};
};
@@ -193,6 +200,7 @@ export function unfollowAccountRequest(id) {
return {
type: ACCOUNT_UNFOLLOW_REQUEST,
id,
+ skipLoading: true,
};
};
@@ -201,6 +209,7 @@ export function unfollowAccountSuccess(relationship, statuses) {
type: ACCOUNT_UNFOLLOW_SUCCESS,
relationship,
statuses,
+ skipLoading: true,
};
};
@@ -208,6 +217,7 @@ export function unfollowAccountFail(error) {
return {
type: ACCOUNT_UNFOLLOW_FAIL,
error,
+ skipLoading: true,
};
};
diff --git a/app/javascript/mastodon/actions/cards.js b/app/javascript/mastodon/actions/cards.js
deleted file mode 100644
index baf04833a..000000000
--- a/app/javascript/mastodon/actions/cards.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import api from '../api';
-
-export const STATUS_CARD_FETCH_REQUEST = 'STATUS_CARD_FETCH_REQUEST';
-export const STATUS_CARD_FETCH_SUCCESS = 'STATUS_CARD_FETCH_SUCCESS';
-export const STATUS_CARD_FETCH_FAIL = 'STATUS_CARD_FETCH_FAIL';
-
-export function fetchStatusCard(id) {
- return (dispatch, getState) => {
- if (getState().getIn(['cards', id], null) !== null) {
- return;
- }
-
- dispatch(fetchStatusCardRequest(id));
-
- api(getState).get(`/api/v1/statuses/${id}/card`).then(response => {
- if (!response.data.url) {
- return;
- }
-
- dispatch(fetchStatusCardSuccess(id, response.data));
- }).catch(error => {
- dispatch(fetchStatusCardFail(id, error));
- });
- };
-};
-
-export function fetchStatusCardRequest(id) {
- return {
- type: STATUS_CARD_FETCH_REQUEST,
- id,
- skipLoading: true,
- };
-};
-
-export function fetchStatusCardSuccess(id, card) {
- return {
- type: STATUS_CARD_FETCH_SUCCESS,
- id,
- card,
- skipLoading: true,
- };
-};
-
-export function fetchStatusCardFail(id, error) {
- return {
- type: STATUS_CARD_FETCH_FAIL,
- id,
- error,
- skipLoading: true,
- skipAlert: true,
- };
-};
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index bb15eb81f..a3c13ada8 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -144,11 +144,13 @@ export function submitCompose(routerHistory) {
}
};
- if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0) {
+ if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {
routerHistory.push('/timelines/direct');
} else if (response.data.visibility !== 'direct') {
insertIfOnline('home');
- } else if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
+ }
+
+ if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
insertIfOnline('community');
insertIfOnline('public');
}
diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js
index a2af3222e..34a4150fa 100644
--- a/app/javascript/mastodon/actions/importer/normalizer.js
+++ b/app/javascript/mastodon/actions/importer/normalizer.js
@@ -14,7 +14,7 @@ export function normalizeAccount(account) {
account = { ...account };
const emojiMap = makeEmojiMap(account);
- const displayName = account.display_name.length === 0 ? account.username : account.display_name;
+ const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
account.note_emojified = emojify(account.note, emojiMap);
diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js
index 8d5e72bec..e7c89b4ba 100644
--- a/app/javascript/mastodon/actions/statuses.js
+++ b/app/javascript/mastodon/actions/statuses.js
@@ -3,7 +3,6 @@ import openDB from '../storage/db';
import { evictStatus } from '../storage/modifier';
import { deleteFromTimelines } from './timelines';
-import { fetchStatusCard } from './cards';
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer';
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
@@ -86,7 +85,6 @@ export function fetchStatus(id) {
const skipLoading = getState().getIn(['statuses', id], null) !== null;
dispatch(fetchContext(id));
- dispatch(fetchStatusCard(id));
if (skipLoading) {
return;
diff --git a/app/javascript/mastodon/actions/suggestions.js b/app/javascript/mastodon/actions/suggestions.js
new file mode 100644
index 000000000..b15bd916b
--- /dev/null
+++ b/app/javascript/mastodon/actions/suggestions.js
@@ -0,0 +1,52 @@
+import api from '../api';
+import { importFetchedAccounts } from './importer';
+
+export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
+export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
+export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL';
+
+export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';
+
+export function fetchSuggestions() {
+ return (dispatch, getState) => {
+ dispatch(fetchSuggestionsRequest());
+
+ api(getState).get('/api/v1/suggestions').then(response => {
+ dispatch(importFetchedAccounts(response.data));
+ dispatch(fetchSuggestionsSuccess(response.data));
+ }).catch(error => dispatch(fetchSuggestionsFail(error)));
+ };
+};
+
+export function fetchSuggestionsRequest() {
+ return {
+ type: SUGGESTIONS_FETCH_REQUEST,
+ skipLoading: true,
+ };
+};
+
+export function fetchSuggestionsSuccess(accounts) {
+ return {
+ type: SUGGESTIONS_FETCH_SUCCESS,
+ accounts,
+ skipLoading: true,
+ };
+};
+
+export function fetchSuggestionsFail(error) {
+ return {
+ type: SUGGESTIONS_FETCH_FAIL,
+ error,
+ skipLoading: true,
+ skipAlert: true,
+ };
+};
+
+export const dismissSuggestion = accountId => (dispatch, getState) => {
+ dispatch({
+ type: SUGGESTIONS_DISMISS,
+ id: accountId,
+ });
+
+ api(getState).delete(`/api/v1/suggestions/${accountId}`);
+};
diff --git a/app/javascript/mastodon/components/account.js b/app/javascript/mastodon/components/account.js
index c021e3267..2bcea8b67 100644
--- a/app/javascript/mastodon/components/account.js
+++ b/app/javascript/mastodon/components/account.js
@@ -30,6 +30,9 @@ class Account extends ImmutablePureComponent {
onMuteNotifications: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
hidden: PropTypes.bool,
+ actionIcon: PropTypes.string,
+ actionTitle: PropTypes.string,
+ onActionClick: PropTypes.func,
};
handleFollow = () => {
@@ -52,8 +55,12 @@ class Account extends ImmutablePureComponent {
this.props.onMuteNotifications(this.props.account, false);
}
+ handleAction = () => {
+ this.props.onActionClick(this.props.account);
+ }
+
render () {
- const { account, intl, hidden } = this.props;
+ const { account, intl, hidden, onActionClick, actionIcon, actionTitle } = this.props;
if (!account) {
return
;
@@ -70,7 +77,9 @@ class Account extends ImmutablePureComponent {
let buttons;
- if (account.get('id') !== me && account.get('relationship', null) !== null) {
+ if (onActionClick && actionIcon) {
+ buttons = ;
+ } else if (account.get('id') !== me && account.get('relationship', null) !== null) {
const following = account.getIn(['relationship', 'following']);
const requested = account.getIn(['relationship', 'requested']);
const blocking = account.getIn(['relationship', 'blocking']);
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 0b23e51f8..fd0780025 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -9,6 +9,7 @@ import DisplayName from './display_name';
import StatusContent from './status_content';
import StatusActionBar from './status_action_bar';
import AttachmentList from './attachment_list';
+import Card from '../features/status/components/card';
import { injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { MediaGallery, Video } from '../features/ui/util/async-components';
@@ -66,6 +67,7 @@ class Status extends ImmutablePureComponent {
unread: PropTypes.bool,
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
+ showThread: PropTypes.bool,
};
// Avoid checking props that are functions (and whose equality will always
@@ -167,7 +169,7 @@ class Status extends ImmutablePureComponent {
let media = null;
let statusAvatar, prepend, rebloggedByText;
- const { intl, hidden, featured, otherAccounts, unread } = this.props;
+ const { intl, hidden, featured, otherAccounts, unread, showThread } = this.props;
let { status, account, ...other } = this.props;
@@ -256,6 +258,14 @@ class Status extends ImmutablePureComponent {
);
}
+ } else if (status.get('spoiler_text').length === 0 && status.get('card')) {
+ media = (
+
+ );
}
if (otherAccounts) {
@@ -300,6 +310,12 @@ class Status extends ImmutablePureComponent {
{media}
+ {showThread && status.get('in_reply_to_id') && status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) && (
+
+ )}
+
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
index bc2f095a6..749d12c08 100644
--- a/app/javascript/mastodon/components/status_action_bar.js
+++ b/app/javascript/mastodon/components/status_action_bar.js
@@ -150,7 +150,6 @@ class StatusActionBar extends ImmutablePureComponent {
let menu = [];
let reblogIcon = 'retweet';
- let replyIcon;
let replyTitle;
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
@@ -193,10 +192,8 @@ class StatusActionBar extends ImmutablePureComponent {
}
if (status.get('in_reply_to_id', null) === null) {
- replyIcon = 'reply';
replyTitle = intl.formatMessage(messages.reply);
} else {
- replyIcon = 'reply-all';
replyTitle = intl.formatMessage(messages.replyAll);
}
@@ -206,7 +203,7 @@ class StatusActionBar extends ImmutablePureComponent {
return (
-
{obfuscatedCount(status.get('replies_count'))}
+
{obfuscatedCount(status.get('replies_count'))}
{shareButton}
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js
index eda7d6ac3..5e3365618 100644
--- a/app/javascript/mastodon/components/status_content.js
+++ b/app/javascript/mastodon/components/status_content.js
@@ -159,7 +159,7 @@ export default class StatusContent extends React.PureComponent {
}
const readMoreButton = (
-