From a5b178094bb41b7023b5f6a73e696fa993b886ee Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 20:56:59 +0900
Subject: [PATCH 01/20] Bump react-toggle from 4.1.1 to 4.1.2 (#15900)

Bumps [react-toggle](https://github.com/aaronshaf/react-toggle) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/aaronshaf/react-toggle/releases)
- [Changelog](https://github.com/aaronshaf/react-toggle/blob/master/CHANGELOG.md)
- [Commits](https://github.com/aaronshaf/react-toggle/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json | 2 +-
 yarn.lock    | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index d4453db851..5ef449f6af 100644
--- a/package.json
+++ b/package.json
@@ -143,7 +143,7 @@
     "react-sparklines": "^1.7.0",
     "react-swipeable-views": "^0.13.9",
     "react-textarea-autosize": "^8.3.2",
-    "react-toggle": "^4.1.1",
+    "react-toggle": "^4.1.2",
     "redis": "^3.0.2",
     "redux": "^4.0.5",
     "redux-immutable": "^4.0.0",
diff --git a/yarn.lock b/yarn.lock
index 7adcc4ab0f..d9a3e3e30f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8988,10 +8988,10 @@ react-textarea-autosize@^8.3.2:
     use-composed-ref "^1.0.0"
     use-latest "^1.0.0"
 
-react-toggle@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.1.1.tgz#2317f67bf918ea3508a96b09dd383efd9da572af"
-  integrity sha512-+wXlMcSpg8SmnIXauMaZiKpR+r2wp2gMUteroejp2UTSqGTVvZLN+m9EhMzFARBKEw7KpQOwzCyfzeHeAndQGw==
+react-toggle@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.1.2.tgz#b00500832f925ad524356d909821821ae39f6c52"
+  integrity sha512-4Ohw31TuYQdhWfA6qlKafeXx3IOH7t4ZHhmRdwsm1fQREwOBGxJT+I22sgHqR/w8JRdk+AeMCJXPImEFSrNXow==
   dependencies:
     classnames "^2.2.5"
 

From 211e5164c41ec57e3b42fd44943d2931e6e710ac Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:02:24 +0900
Subject: [PATCH 02/20] Bump @babel/core from 7.13.8 to 7.13.10 (#15902)

Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.13.8 to 7.13.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.13.10/packages/babel-core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 48 ++++++++++++++++++++++++------------------------
 2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/package.json b/package.json
index 5ef449f6af..b4ab384690 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
   },
   "private": true,
   "dependencies": {
-    "@babel/core": "^7.13.8",
+    "@babel/core": "^7.13.10",
     "@babel/plugin-proposal-class-properties": "^7.8.3",
     "@babel/plugin-proposal-decorators": "^7.13.5",
     "@babel/plugin-transform-react-inline-elements": "^7.12.13",
diff --git a/yarn.lock b/yarn.lock
index d9a3e3e30f..9a3651c53c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -21,17 +21,17 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.8.tgz#5b783b9808f15cef71547f1b691f34f8ff6003a6"
   integrity sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==
 
-"@babel/core@^7.1.0", "@babel/core@^7.13.8", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
-  version "7.13.8"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.8.tgz#c191d9c5871788a591d69ea1dc03e5843a3680fb"
-  integrity sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==
+"@babel/core@^7.1.0", "@babel/core@^7.13.10", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559"
+  integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==
   dependencies:
     "@babel/code-frame" "^7.12.13"
-    "@babel/generator" "^7.13.0"
-    "@babel/helper-compilation-targets" "^7.13.8"
+    "@babel/generator" "^7.13.9"
+    "@babel/helper-compilation-targets" "^7.13.10"
     "@babel/helper-module-transforms" "^7.13.0"
-    "@babel/helpers" "^7.13.0"
-    "@babel/parser" "^7.13.4"
+    "@babel/helpers" "^7.13.10"
+    "@babel/parser" "^7.13.10"
     "@babel/template" "^7.12.13"
     "@babel/traverse" "^7.13.0"
     "@babel/types" "^7.13.0"
@@ -43,10 +43,10 @@
     semver "^6.3.0"
     source-map "^0.5.0"
 
-"@babel/generator@^7.13.0":
-  version "7.13.0"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.0.tgz#bd00d4394ca22f220390c56a0b5b85568ec1ec0c"
-  integrity sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw==
+"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
+  version "7.13.9"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
+  integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
   dependencies:
     "@babel/types" "^7.13.0"
     jsesc "^2.5.1"
@@ -82,10 +82,10 @@
     "@babel/helper-annotate-as-pure" "^7.12.13"
     "@babel/types" "^7.12.13"
 
-"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.8":
-  version "7.13.8"
-  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz#02bdb22783439afb11b2f009814bdd88384bd468"
-  integrity sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==
+"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.13.8":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz#1310a1678cb8427c07a753750da4f8ce442bdd0c"
+  integrity sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==
   dependencies:
     "@babel/compat-data" "^7.13.8"
     "@babel/helper-validator-option" "^7.12.17"
@@ -274,10 +274,10 @@
     "@babel/traverse" "^7.13.0"
     "@babel/types" "^7.13.0"
 
-"@babel/helpers@^7.13.0":
-  version "7.13.0"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.0.tgz#7647ae57377b4f0408bf4f8a7af01c42e41badc0"
-  integrity sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==
+"@babel/helpers@^7.13.10":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
+  integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
   dependencies:
     "@babel/template" "^7.12.13"
     "@babel/traverse" "^7.13.0"
@@ -292,10 +292,10 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.4", "@babel/parser@^7.7.0":
-  version "7.13.4"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab"
-  integrity sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==
+"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.7.0":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.10.tgz#8f8f9bf7b3afa3eabd061f7a5bcdf4fec3c48409"
+  integrity sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ==
 
 "@babel/plugin-proposal-async-generator-functions@^7.13.8":
   version "7.13.8"

From 9cd6a076b79c4d259b8cfbde00a75984217da0a7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:03:02 +0900
Subject: [PATCH 03/20] Bump css-loader from 5.1.1 to 5.1.2 (#15905)

Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/compare/v5.1.1...v5.1.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 25 +++++++++++++++----------
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/package.json b/package.json
index b4ab384690..7d14502275 100644
--- a/package.json
+++ b/package.json
@@ -86,7 +86,7 @@
     "color-blend": "^3.0.1",
     "compression-webpack-plugin": "^6.1.1",
     "cross-env": "^7.0.3",
-    "css-loader": "^5.1.1",
+    "css-loader": "^5.1.2",
     "cssnano": "^4.1.10",
     "detect-passive-events": "^2.0.3",
     "dotenv": "^8.2.0",
diff --git a/yarn.lock b/yarn.lock
index 9a3651c53c..5b08287b99 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3055,6 +3055,11 @@ colorette@^1.2.1:
   resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
   integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
 
+colorette@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+  integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+
 combined-stream@^1.0.6, combined-stream@~1.0.6:
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -3368,16 +3373,16 @@ css-list-helpers@^1.0.1:
   dependencies:
     tcomb "^2.5.0"
 
-css-loader@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.1.1.tgz#9362d444a0f7c08c148a109596715c904e252879"
-  integrity sha512-5FfhpjwtuRgxqmusDidowqmLlcb+1HgnEDMsi2JhiUrZUcoc+cqw+mUtMIF/+OfeMYaaFCLYp1TaIt9H6I/fKA==
+css-loader@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.1.2.tgz#b93dba498ec948b543b49d4fab5017205d4f5c3e"
+  integrity sha512-T7vTXHSx0KrVEg/xjcl7G01RcVXpcw4OELwDPvkr7izQNny85A84dK3dqrczuEfBcu7Yg7mdTjJLSTibRUoRZg==
   dependencies:
     camelcase "^6.2.0"
     cssesc "^3.0.0"
     icss-utils "^5.1.0"
     loader-utils "^2.0.0"
-    postcss "^8.2.6"
+    postcss "^8.2.8"
     postcss-modules-extract-imports "^3.0.0"
     postcss-modules-local-by-default "^4.0.0"
     postcss-modules-scope "^3.0.0"
@@ -8474,12 +8479,12 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27, postcss@^7.0.32:
     source-map "^0.6.1"
     supports-color "^6.1.0"
 
-postcss@^8.2.6:
-  version "8.2.6"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe"
-  integrity sha512-xpB8qYxgPuly166AGlpRjUdEYtmOWx2iCwGmrv4vqZL9YPVviDVPZPRXxnXr6xPZOdxQ9lp3ZBFCRgWJ7LE3Sg==
+postcss@^8.2.8:
+  version "8.2.8"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.8.tgz#0b90f9382efda424c4f0f69a2ead6f6830d08ece"
+  integrity sha512-1F0Xb2T21xET7oQV9eKuctbM9S7BC0fetoHCc4H13z0PT6haiRLP4T0ZY4XWh7iLP0usgqykT6p9B2RtOf4FPw==
   dependencies:
-    colorette "^1.2.1"
+    colorette "^1.2.2"
     nanoid "^3.1.20"
     source-map "^0.6.1"
 

From 89ff042292a0c5c434105561ea2b51ea6c1597d8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:03:19 +0900
Subject: [PATCH 04/20] Bump eslint from 7.21.0 to 7.22.0 (#15906)

Bumps [eslint](https://github.com/eslint/eslint) from 7.21.0 to 7.22.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.21.0...v7.22.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 24 ++++++++++++++++++------
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/package.json b/package.json
index 7d14502275..52ff2959dc 100644
--- a/package.json
+++ b/package.json
@@ -176,7 +176,7 @@
     "@testing-library/react": "^11.2.5",
     "babel-eslint": "^10.1.0",
     "babel-jest": "^26.6.3",
-    "eslint": "^7.21.0",
+    "eslint": "^7.22.0",
     "eslint-plugin-import": "~2.22.1",
     "eslint-plugin-jsx-a11y": "~6.4.1",
     "eslint-plugin-promise": "~4.3.1",
diff --git a/yarn.lock b/yarn.lock
index 5b08287b99..4572da4bdf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4336,10 +4336,10 @@ eslint@^2.7.0:
     text-table "~0.2.0"
     user-home "^2.0.0"
 
-eslint@^7.21.0:
-  version "7.21.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83"
-  integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==
+eslint@^7.22.0:
+  version "7.22.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f"
+  integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==
   dependencies:
     "@babel/code-frame" "7.12.11"
     "@eslint/eslintrc" "^0.4.0"
@@ -4358,7 +4358,7 @@ eslint@^7.21.0:
     file-entry-cache "^6.0.1"
     functional-red-black-tree "^1.0.1"
     glob-parent "^5.0.0"
-    globals "^12.1.0"
+    globals "^13.6.0"
     ignore "^4.0.6"
     import-fresh "^3.0.0"
     imurmurhash "^0.1.4"
@@ -4366,7 +4366,7 @@ eslint@^7.21.0:
     js-yaml "^3.13.1"
     json-stable-stringify-without-jsonify "^1.0.1"
     levn "^0.4.1"
-    lodash "^4.17.20"
+    lodash "^4.17.21"
     minimatch "^3.0.4"
     natural-compare "^1.4.0"
     optionator "^0.9.1"
@@ -5112,6 +5112,13 @@ globals@^12.1.0:
   dependencies:
     type-fest "^0.8.1"
 
+globals@^13.6.0:
+  version "13.6.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.6.0.tgz#d77138e53738567bb96a3916ff6f6b487af20ef7"
+  integrity sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ==
+  dependencies:
+    type-fest "^0.20.2"
+
 globals@^9.2.0:
   version "9.18.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
@@ -10771,6 +10778,11 @@ type-fest@^0.11.0:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
   integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
 
+type-fest@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
 type-fest@^0.6.0:
   version "0.6.0"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"

From aa97433e00352afcd7c0af7e972bdadff9640a09 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:03:46 +0900
Subject: [PATCH 05/20] Bump @babel/preset-env from 7.13.9 to 7.13.10 (#15901)

Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.13.9 to 7.13.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.13.10/packages/babel-preset-env)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json |  2 +-
 yarn.lock    | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/package.json b/package.json
index 52ff2959dc..42aae91718 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,7 @@
     "@babel/plugin-proposal-decorators": "^7.13.5",
     "@babel/plugin-transform-react-inline-elements": "^7.12.13",
     "@babel/plugin-transform-runtime": "^7.13.9",
-    "@babel/preset-env": "^7.13.9",
+    "@babel/preset-env": "^7.13.10",
     "@babel/preset-react": "^7.12.13",
     "@babel/runtime": "^7.13.9",
     "@clusterws/cws": "^3.0.0",
diff --git a/yarn.lock b/yarn.lock
index 4572da4bdf..2344b8e49b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -828,13 +828,13 @@
     "@babel/helper-create-regexp-features-plugin" "^7.12.13"
     "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/preset-env@^7.13.9":
-  version "7.13.9"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.9.tgz#3ee5f233316b10d066d7f379c6d1e13a96853654"
-  integrity sha512-mcsHUlh2rIhViqMG823JpscLMesRt3QbMsv1+jhopXEb3W2wXvQ9QoiOlZI9ZbR3XqPtaFpZwEZKYqGJnGMZTQ==
+"@babel/preset-env@^7.13.10":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.10.tgz#b5cde31d5fe77ab2a6ab3d453b59041a1b3a5252"
+  integrity sha512-nOsTScuoRghRtUsRr/c69d042ysfPHcu+KOB4A9aAO9eJYqrkat+LF8G1yp1HD18QiwixT2CisZTr/0b3YZPXQ==
   dependencies:
     "@babel/compat-data" "^7.13.8"
-    "@babel/helper-compilation-targets" "^7.13.8"
+    "@babel/helper-compilation-targets" "^7.13.10"
     "@babel/helper-plugin-utils" "^7.13.0"
     "@babel/helper-validator-option" "^7.12.17"
     "@babel/plugin-proposal-async-generator-functions" "^7.13.8"

From 8066f7baf0282213d4bbcc660b9b8c9d4fab53b6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:04:03 +0900
Subject: [PATCH 06/20] Bump @babel/runtime from 7.13.9 to 7.13.10 (#15904)

Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.13.9 to 7.13.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.13.10/packages/babel-runtime)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json | 2 +-
 yarn.lock    | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index 42aae91718..ad9d1e4355 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
     "@babel/plugin-transform-runtime": "^7.13.9",
     "@babel/preset-env": "^7.13.10",
     "@babel/preset-react": "^7.12.13",
-    "@babel/runtime": "^7.13.9",
+    "@babel/runtime": "^7.13.10",
     "@clusterws/cws": "^3.0.0",
     "@gamestdio/websocket": "^0.3.2",
     "@github/webauthn-json": "^0.5.7",
diff --git a/yarn.lock b/yarn.lock
index 2344b8e49b..94d55ee1fb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -939,10 +939,10 @@
   dependencies:
     regenerator-runtime "^0.12.0"
 
-"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.9", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
-  version "7.13.9"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.9.tgz#97dbe2116e2630c489f22e0656decd60aaa1fcee"
-  integrity sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
+  integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
   dependencies:
     regenerator-runtime "^0.13.4"
 

From 506010abc53087f23c518c7576e878a18d9abdd1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Mar 2021 21:19:16 +0900
Subject: [PATCH 07/20] Bump bundler-audit from 0.7.0.1 to 0.8.0 (#15877)

Bumps [bundler-audit](https://github.com/postmodern/bundler-audit) from 0.7.0.1 to 0.8.0.
- [Release notes](https://github.com/postmodern/bundler-audit/releases)
- [Changelog](https://github.com/rubysec/bundler-audit/blob/master/ChangeLog.md)
- [Commits](https://github.com/postmodern/bundler-audit/compare/v0.7.0.1...v0.8.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Gemfile      | 2 +-
 Gemfile.lock | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Gemfile b/Gemfile
index 2bdf6118ea..7a5b119b84 100644
--- a/Gemfile
+++ b/Gemfile
@@ -141,7 +141,7 @@ group :development do
   gem 'rubocop', '~> 1.11', require: false
   gem 'rubocop-rails', '~> 2.9', require: false
   gem 'brakeman', '~> 4.10', require: false
-  gem 'bundler-audit', '~> 0.7', require: false
+  gem 'bundler-audit', '~> 0.8', require: false
 
   gem 'capistrano', '~> 3.16'
   gem 'capistrano-rails', '~> 1.6'
diff --git a/Gemfile.lock b/Gemfile.lock
index 7b3d113196..ec63daf5f6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -115,9 +115,9 @@ GEM
     bullet (6.1.4)
       activesupport (>= 3.0.0)
       uniform_notifier (~> 1.11)
-    bundler-audit (0.7.0.1)
+    bundler-audit (0.8.0)
       bundler (>= 1.2.0, < 3)
-      thor (>= 0.18, < 2)
+      thor (~> 1.0)
     byebug (11.1.3)
     capistrano (3.16.0)
       airbrussh (>= 1.0.0)
@@ -705,7 +705,7 @@ DEPENDENCIES
   brakeman (~> 4.10)
   browser
   bullet (~> 6.1)
-  bundler-audit (~> 0.7)
+  bundler-audit (~> 0.8)
   capistrano (~> 3.16)
   capistrano-rails (~> 1.6)
   capistrano-rbenv (~> 2.2)

From 0c9ce7b451258b9628fadd92b2b7d92e9f297a29 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 16 Mar 2021 07:52:23 +0900
Subject: [PATCH 08/20] Bump @babel/plugin-transform-runtime from 7.13.9 to
 7.13.10 (#15903)

Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.13.9 to 7.13.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.13.10/packages/babel-plugin-transform-runtime)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 package.json | 2 +-
 yarn.lock    | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index ad9d1e4355..fd766cc8c1 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
     "@babel/plugin-proposal-class-properties": "^7.8.3",
     "@babel/plugin-proposal-decorators": "^7.13.5",
     "@babel/plugin-transform-react-inline-elements": "^7.12.13",
-    "@babel/plugin-transform-runtime": "^7.13.9",
+    "@babel/plugin-transform-runtime": "^7.13.10",
     "@babel/preset-env": "^7.13.10",
     "@babel/preset-react": "^7.12.13",
     "@babel/runtime": "^7.13.10",
diff --git a/yarn.lock b/yarn.lock
index 94d55ee1fb..3cc2c7f83e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -765,10 +765,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-runtime@^7.13.9":
-  version "7.13.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.13.9.tgz#744d3103338a0d6c90dee0497558150b490cee07"
-  integrity sha512-XCxkY/wBI6M6Jj2mlWxkmqbKPweRanszWbF3Tyut+hKh+PHcuIH/rSr/7lmmE7C3WW+HSIm2GT+d5jwmheuB0g==
+"@babel/plugin-transform-runtime@^7.13.10":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.13.10.tgz#a1e40d22e2bf570c591c9c7e5ab42d6bf1e419e1"
+  integrity sha512-Y5k8ipgfvz5d/76tx7JYbKQTcgFSU6VgJ3kKQv4zGTKr+a9T/KBvfRvGtSFgKDQGt/DBykQixV0vNWKIdzWErA==
   dependencies:
     "@babel/helper-module-imports" "^7.12.13"
     "@babel/helper-plugin-utils" "^7.13.0"

From 9cb6bc56faab374c1c740c7093d5271d37201aed Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 16 Mar 2021 07:55:43 +0900
Subject: [PATCH 09/20] Bump rspec-rails from 4.1.0 to 5.0.0 (#15876)

Bumps [rspec-rails](https://github.com/rspec/rspec-rails) from 4.1.0 to 5.0.0.
- [Release notes](https://github.com/rspec/rspec-rails/releases)
- [Changelog](https://github.com/rspec/rspec-rails/blob/main/Changelog.md)
- [Commits](https://github.com/rspec/rspec-rails/compare/v4.1.0...v5.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 Gemfile      |  2 +-
 Gemfile.lock | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Gemfile b/Gemfile
index 7a5b119b84..5117962391 100644
--- a/Gemfile
+++ b/Gemfile
@@ -109,7 +109,7 @@ group :development, :test do
   gem 'i18n-tasks', '~> 0.9', require: false
   gem 'pry-byebug', '~> 3.9'
   gem 'pry-rails', '~> 0.3'
-  gem 'rspec-rails', '~> 4.1'
+  gem 'rspec-rails', '~> 5.0'
 end
 
 group :production, :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index ec63daf5f6..d2037b3bce 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -530,10 +530,10 @@ GEM
     rspec-mocks (3.10.2)
       diff-lcs (>= 1.2.0, < 2.0)
       rspec-support (~> 3.10.0)
-    rspec-rails (4.1.0)
-      actionpack (>= 4.2)
-      activesupport (>= 4.2)
-      railties (>= 4.2)
+    rspec-rails (5.0.0)
+      actionpack (>= 5.2)
+      activesupport (>= 5.2)
+      railties (>= 5.2)
       rspec-core (~> 3.10)
       rspec-expectations (~> 3.10)
       rspec-mocks (~> 3.10)
@@ -792,7 +792,7 @@ DEPENDENCIES
   redis-namespace (~> 1.8)
   redis-rails (~> 5.0)
   rqrcode (~> 1.2)
-  rspec-rails (~> 4.1)
+  rspec-rails (~> 5.0)
   rspec-sidekiq (~> 3.1)
   rspec_junit_formatter (~> 0.4)
   rubocop (~> 1.11)

From 43eff898a0b0f31aaf042d9d387aaece2627a01d Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Wed, 17 Mar 2021 10:09:55 +0100
Subject: [PATCH 10/20] Prepare Mastodon for Rails 6 (#15911)

* Fix misuse of foreign_type

* Fix use of removed "add_template_helper"

* Use response.media_type instead of response.content_type in tests

* Fix CSV export controller test on Rails 6

Rails 6 sets a "filename*" field in the Content-Disposition header to
explicitly encode the filename as UTF-8.

This changes checks the first part of the Content-Disposition header so
it matches in both Rails 5 and Rails 6.

* Fix emoji formatting with Rails 6

* Make emoji output more idiomatic and robust

* Switch from redis-rails gem to built-in Rails redis cache storage
---
 Gemfile                                         |  1 -
 Gemfile.lock                                    | 17 -----------------
 app/lib/formatter.rb                            |  4 ++--
 app/mailers/notification_mailer.rb              |  2 +-
 app/mailers/user_mailer.rb                      |  2 +-
 app/models/notification.rb                      | 12 ++++++------
 config/environments/development.rb              |  2 +-
 config/environments/production.rb               |  2 +-
 config/initializers/sidekiq.rb                  |  2 +-
 lib/mastodon/redis_config.rb                    |  2 ++
 spec/controllers/accounts_controller_spec.rb    |  8 ++++----
 .../activitypub/collections_controller_spec.rb  |  8 ++++----
 ...ollowers_synchronizations_controller_spec.rb |  2 +-
 .../activitypub/outboxes_controller_spec.rb     | 12 ++++++------
 .../activitypub/replies_controller_spec.rb      |  4 ++--
 .../concerns/export_controller_concern_spec.rb  |  4 ++--
 .../well_known/host_meta_controller_spec.rb     |  2 +-
 .../keybase_proof_config_controller_spec.rb     |  2 +-
 .../well_known/nodeinfo_controller_spec.rb      |  4 ++--
 .../well_known/webfinger_controller_spec.rb     |  2 +-
 spec/requests/catch_all_route_request_spec.rb   |  4 ++--
 spec/requests/host_meta_request_spec.rb         |  2 +-
 spec/requests/webfinger_request_spec.rb         |  6 +++---
 23 files changed, 45 insertions(+), 61 deletions(-)

diff --git a/Gemfile b/Gemfile
index 5117962391..c3f50ec30c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -153,7 +153,6 @@ end
 
 group :production do
   gem 'lograge', '~> 0.11'
-  gem 'redis-rails', '~> 5.0'
 end
 
 gem 'concurrent-ruby', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index d2037b3bce..106c13554c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -491,24 +491,8 @@ GEM
     rdf-normalize (0.4.0)
       rdf (~> 3.1)
     redis (4.2.5)
-    redis-actionpack (5.2.0)
-      actionpack (>= 5, < 7)
-      redis-rack (>= 2.1.0, < 3)
-      redis-store (>= 1.1.0, < 2)
-    redis-activesupport (5.2.0)
-      activesupport (>= 3, < 7)
-      redis-store (>= 1.3, < 2)
     redis-namespace (1.8.1)
       redis (>= 3.0.4)
-    redis-rack (2.1.3)
-      rack (>= 2.0.8, < 3)
-      redis-store (>= 1.2, < 2)
-    redis-rails (5.0.2)
-      redis-actionpack (>= 5.0, < 6)
-      redis-activesupport (>= 5.0, < 6)
-      redis-store (>= 1.2, < 2)
-    redis-store (1.9.0)
-      redis (>= 4, < 5)
     regexp_parser (2.1.1)
     request_store (1.5.0)
       rack (>= 1.4)
@@ -790,7 +774,6 @@ DEPENDENCIES
   rdf-normalize (~> 0.4)
   redis (~> 4.2)
   redis-namespace (~> 1.8)
-  redis-rails (~> 5.0)
   rqrcode (~> 1.2)
   rspec-rails (~> 5.0)
   rspec-sidekiq (~> 3.1)
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 7252234d6a..6fb5d54199 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -158,9 +158,9 @@ class Formatter
           original_url, static_url = emoji
           replacement = begin
             if animate
-              "<img draggable=\"false\" class=\"emojione\" alt=\":#{encode(shortcode)}:\" title=\":#{encode(shortcode)}:\" src=\"#{encode(original_url)}\" />"
+              image_tag(original_url, draggable: false, class: 'emojione', alt: ":#{shortcode}:", title: ":#{shortcode}:")
             else
-              "<img draggable=\"false\" class=\"emojione custom-emoji\" alt=\":#{encode(shortcode)}:\" title=\":#{encode(shortcode)}:\" src=\"#{encode(static_url)}\" data-original=\"#{original_url}\" data-static=\"#{static_url}\" />"
+              image_tag(original_url, draggable: false, class: 'emojione custom-emoji', alt: ":#{shortcode}:", title: ":#{shortcode}:", data: { original: original_url, static: static_url })
             end
           end
           before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''
diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb
index 54db892ccc..9e683b6a16 100644
--- a/app/mailers/notification_mailer.rb
+++ b/app/mailers/notification_mailer.rb
@@ -4,7 +4,7 @@ class NotificationMailer < ApplicationMailer
   helper :accounts
   helper :statuses
 
-  add_template_helper RoutingHelper
+  helper RoutingHelper
 
   def mention(recipient, notification)
     @me     = recipient
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index 95996ba3ff..68d1c4507e 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -8,7 +8,7 @@ class UserMailer < Devise::Mailer
   helper :instance
   helper :statuses
 
-  add_template_helper RoutingHelper
+  helper RoutingHelper
 
   def confirmation_instructions(user, token, **)
     @resource = user
diff --git a/app/models/notification.rb b/app/models/notification.rb
index 98a6a618f5..3bf9dd483e 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -49,12 +49,12 @@ class Notification < ApplicationRecord
   belongs_to :from_account, class_name: 'Account', optional: true
   belongs_to :activity, polymorphic: true, optional: true
 
-  belongs_to :mention,        foreign_type: 'Mention',       foreign_key: 'activity_id', optional: true
-  belongs_to :status,         foreign_type: 'Status',        foreign_key: 'activity_id', optional: true
-  belongs_to :follow,         foreign_type: 'Follow',        foreign_key: 'activity_id', optional: true
-  belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id', optional: true
-  belongs_to :favourite,      foreign_type: 'Favourite',     foreign_key: 'activity_id', optional: true
-  belongs_to :poll,           foreign_type: 'Poll',          foreign_key: 'activity_id', optional: true
+  belongs_to :mention,        foreign_key: 'activity_id', optional: true
+  belongs_to :status,         foreign_key: 'activity_id', optional: true
+  belongs_to :follow,         foreign_key: 'activity_id', optional: true
+  belongs_to :follow_request, foreign_key: 'activity_id', optional: true
+  belongs_to :favourite,      foreign_key: 'activity_id', optional: true
+  belongs_to :poll,           foreign_key: 'activity_id', optional: true
 
   validates :type, inclusion: { in: TYPES }
 
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 0791b82ab6..d76361c602 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -17,7 +17,7 @@ Rails.application.configure do
   if Rails.root.join('tmp/caching-dev.txt').exist?
     config.action_controller.perform_caching = true
 
-    config.cache_store = :redis_store, ENV['REDIS_URL'], REDIS_CACHE_PARAMS
+    config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS
 
     config.public_file_server.headers = {
       'Cache-Control' => "public, max-age=#{2.days.to_i}",
diff --git a/config/environments/production.rb b/config/environments/production.rb
index aaad2449f2..81a67902ea 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -52,7 +52,7 @@ Rails.application.configure do
   config.log_tags = [:request_id]
 
   # Use a different cache store in production.
-  config.cache_store = :redis_store, ENV['CACHE_REDIS_URL'], REDIS_CACHE_PARAMS
+  config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS
 
   # Ignore bad email addresses and do not raise email delivery errors.
   # Set this to true and configure the email server for immediate delivery to raise delivery errors.
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 9d348ddd08..fc85a39137 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 namespace    = ENV.fetch('REDIS_NAMESPACE') { nil }
-redis_params = { url: ENV['REDIS_URL'] }
+redis_params = { url: ENV['REDIS_URL'], driver: :hiredis }
 
 if namespace
   redis_params[:namespace] = namespace
diff --git a/lib/mastodon/redis_config.rb b/lib/mastodon/redis_config.rb
index c3c8ff8005..3f2a8f7c26 100644
--- a/lib/mastodon/redis_config.rb
+++ b/lib/mastodon/redis_config.rb
@@ -27,6 +27,8 @@ namespace       = ENV.fetch('REDIS_NAMESPACE', nil)
 cache_namespace = namespace ? namespace + '_cache' : 'cache'
 
 REDIS_CACHE_PARAMS = {
+  driver: :hiredis,
+  url: ENV['REDIS_URL'],
   expires_in: 10.minutes,
   namespace: cache_namespace,
 }.freeze
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index f7d0b1af54..ac426b01e6 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -370,7 +370,7 @@ RSpec.describe AccountsController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it_behaves_like 'cachable response'
@@ -402,7 +402,7 @@ RSpec.describe AccountsController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns public Cache-Control header' do
@@ -428,7 +428,7 @@ RSpec.describe AccountsController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it_behaves_like 'cachable response'
@@ -446,7 +446,7 @@ RSpec.describe AccountsController, type: :controller do
           end
 
           it 'returns application/activity+json' do
-            expect(response.content_type).to eq 'application/activity+json'
+            expect(response.media_type).to eq 'application/activity+json'
           end
 
           it 'returns private Cache-Control header' do
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb
index ac661e5e1d..d584136ff5 100644
--- a/spec/controllers/activitypub/collections_controller_spec.rb
+++ b/spec/controllers/activitypub/collections_controller_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it_behaves_like 'cachable response'
@@ -88,7 +88,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
           end
 
           it 'returns application/activity+json' do
-            expect(response.content_type).to eq 'application/activity+json'
+            expect(response.media_type).to eq 'application/activity+json'
           end
 
           it_behaves_like 'cachable response'
@@ -116,7 +116,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
             end
 
             it 'returns application/activity+json' do
-              expect(response.content_type).to eq 'application/activity+json'
+              expect(response.media_type).to eq 'application/activity+json'
             end
 
             it 'returns private Cache-Control header' do
@@ -141,7 +141,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
             end
 
             it 'returns application/activity+json' do
-              expect(response.content_type).to eq 'application/activity+json'
+              expect(response.media_type).to eq 'application/activity+json'
             end
 
             it 'returns private Cache-Control header' do
diff --git a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
index 88f4554c2d..d373f56bdb 100644
--- a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
+++ b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controll
       end
 
       it 'returns application/activity+json' do
-        expect(response.content_type).to eq 'application/activity+json'
+        expect(response.media_type).to eq 'application/activity+json'
       end
 
       it 'returns orderedItems with followers from example.com' do
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
index 84e3a89560..d23f2c17cb 100644
--- a/spec/controllers/activitypub/outboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns totalItems' do
@@ -85,7 +85,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns orderedItems with public or unlisted statuses' do
@@ -133,7 +133,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns orderedItems with public or unlisted statuses' do
@@ -159,7 +159,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns orderedItems with private statuses' do
@@ -185,7 +185,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns empty orderedItems' do
@@ -210,7 +210,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it 'returns empty orderedItems' do
diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb
index 2502597528..bf82fd0207 100644
--- a/spec/controllers/activitypub/replies_controller_spec.rb
+++ b/spec/controllers/activitypub/replies_controller_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
         end
 
         it 'returns application/activity+json' do
-          expect(response.content_type).to eq 'application/activity+json'
+          expect(response.media_type).to eq 'application/activity+json'
         end
 
         it_behaves_like 'cachable response'
@@ -120,7 +120,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
           end
 
           it 'returns application/activity+json' do
-            expect(response.content_type).to eq 'application/activity+json'
+            expect(response.media_type).to eq 'application/activity+json'
           end
 
           it_behaves_like 'cachable response'
diff --git a/spec/controllers/concerns/export_controller_concern_spec.rb b/spec/controllers/concerns/export_controller_concern_spec.rb
index fce129bee2..1a5e46f8ef 100644
--- a/spec/controllers/concerns/export_controller_concern_spec.rb
+++ b/spec/controllers/concerns/export_controller_concern_spec.rb
@@ -22,8 +22,8 @@ describe ApplicationController, type: :controller do
       get :index, format: :csv
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'text/csv'
-      expect(response.headers['Content-Disposition']).to eq 'attachment; filename="anonymous.csv"'
+      expect(response.media_type).to eq 'text/csv'
+      expect(response.headers['Content-Disposition']).to start_with 'attachment; filename="anonymous.csv"'
       expect(response.body).to eq user.account.username
     end
 
diff --git a/spec/controllers/well_known/host_meta_controller_spec.rb b/spec/controllers/well_known/host_meta_controller_spec.rb
index 643ba9cd32..c02aa0d596 100644
--- a/spec/controllers/well_known/host_meta_controller_spec.rb
+++ b/spec/controllers/well_known/host_meta_controller_spec.rb
@@ -8,7 +8,7 @@ describe WellKnown::HostMetaController, type: :controller do
       get :show, format: :xml
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/xrd+xml'
+      expect(response.media_type).to eq 'application/xrd+xml'
       expect(response.body).to eq <<XML
 <?xml version="1.0" encoding="UTF-8"?>
 <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
diff --git a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb b/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
index 9067e676de..00f251c3c6 100644
--- a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
+++ b/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
@@ -8,7 +8,7 @@ describe WellKnown::KeybaseProofConfigController, type: :controller do
       get :show
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/json'
+      expect(response.media_type).to eq 'application/json'
       expect { JSON.parse(response.body) }.not_to raise_exception
     end
   end
diff --git a/spec/controllers/well_known/nodeinfo_controller_spec.rb b/spec/controllers/well_known/nodeinfo_controller_spec.rb
index 12e1fa4159..694bb0fb9f 100644
--- a/spec/controllers/well_known/nodeinfo_controller_spec.rb
+++ b/spec/controllers/well_known/nodeinfo_controller_spec.rb
@@ -8,7 +8,7 @@ describe WellKnown::NodeInfoController, type: :controller do
       get :index
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/json'
+      expect(response.media_type).to eq 'application/json'
 
       json = body_as_json
 
@@ -23,7 +23,7 @@ describe WellKnown::NodeInfoController, type: :controller do
       get :show
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/json'
+      expect(response.media_type).to eq 'application/json'
 
       json = body_as_json
 
diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb
index cf7005b0e7..1075456f33 100644
--- a/spec/controllers/well_known/webfinger_controller_spec.rb
+++ b/spec/controllers/well_known/webfinger_controller_spec.rb
@@ -25,7 +25,7 @@ describe WellKnown::WebfingerController, type: :controller do
       end
 
       it 'returns application/jrd+json' do
-        expect(response.content_type).to eq 'application/jrd+json'
+        expect(response.media_type).to eq 'application/jrd+json'
       end
 
       it 'returns links for the account' do
diff --git a/spec/requests/catch_all_route_request_spec.rb b/spec/requests/catch_all_route_request_spec.rb
index 22ce1cf59f..f965f55221 100644
--- a/spec/requests/catch_all_route_request_spec.rb
+++ b/spec/requests/catch_all_route_request_spec.rb
@@ -6,7 +6,7 @@ describe "The catch all route" do
       get "/test"
 
       expect(response.status).to eq 404
-      expect(response.content_type).to eq "text/html"
+      expect(response.media_type).to eq "text/html"
     end
   end
 
@@ -15,7 +15,7 @@ describe "The catch all route" do
       get "/test.test"
 
       expect(response.status).to eq 404
-      expect(response.content_type).to eq "text/html"
+      expect(response.media_type).to eq "text/html"
     end
   end
 end
diff --git a/spec/requests/host_meta_request_spec.rb b/spec/requests/host_meta_request_spec.rb
index beb33a859e..0ca6414613 100644
--- a/spec/requests/host_meta_request_spec.rb
+++ b/spec/requests/host_meta_request_spec.rb
@@ -6,7 +6,7 @@ describe "The host_meta route" do
       get host_meta_url
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq "application/xrd+xml"
+      expect(response.media_type).to eq "application/xrd+xml"
     end
   end
 end
diff --git a/spec/requests/webfinger_request_spec.rb b/spec/requests/webfinger_request_spec.rb
index 48823714e2..209fda72aa 100644
--- a/spec/requests/webfinger_request_spec.rb
+++ b/spec/requests/webfinger_request_spec.rb
@@ -8,7 +8,7 @@ describe 'The webfinger route' do
       get webfinger_url(resource: alice.to_webfinger_s)
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/jrd+json'
+      expect(response.media_type).to eq 'application/jrd+json'
     end
   end
 
@@ -17,7 +17,7 @@ describe 'The webfinger route' do
       get webfinger_url(resource: alice.to_webfinger_s, format: :json)
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/jrd+json'
+      expect(response.media_type).to eq 'application/jrd+json'
     end
 
     it 'returns a json response for json accept header' do
@@ -25,7 +25,7 @@ describe 'The webfinger route' do
       get webfinger_url(resource: alice.to_webfinger_s), headers: headers
 
       expect(response).to have_http_status(200)
-      expect(response.content_type).to eq 'application/jrd+json'
+      expect(response.media_type).to eq 'application/jrd+json'
     end
   end
 end

From 5027abecd1e5e511064de75fb5248139e1c8fe23 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Thu, 18 Mar 2021 00:41:32 +0100
Subject: [PATCH 11/20] Fix cache_collection crashing when given an empty
 collection (#15921)

* Fix cache_collection crashing when given an empty collection

* Add tests
---
 app/controllers/concerns/cache_concern.rb     |  4 +-
 app/lib/entity_cache.rb                       |  4 +-
 .../concerns/cache_concern_spec.rb            | 40 +++++++++++++++++++
 spec/lib/entity_cache_spec.rb                 | 19 +++++++++
 4 files changed, 65 insertions(+), 2 deletions(-)
 create mode 100644 spec/controllers/concerns/cache_concern_spec.rb
 create mode 100644 spec/lib/entity_cache_spec.rb

diff --git a/app/controllers/concerns/cache_concern.rb b/app/controllers/concerns/cache_concern.rb
index 3fb4b962a3..05e431b19a 100644
--- a/app/controllers/concerns/cache_concern.rb
+++ b/app/controllers/concerns/cache_concern.rb
@@ -31,7 +31,9 @@ module CacheConcern
   def cache_collection(raw, klass)
     return raw unless klass.respond_to?(:with_includes)
 
-    raw                    = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
+    raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
+    return [] if raw.empty?
+
     cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id)
     uncached_ids           = raw.map(&:id) - cached_keys_with_value.keys
 
diff --git a/app/lib/entity_cache.rb b/app/lib/entity_cache.rb
index 5d51e85852..80b0046eea 100644
--- a/app/lib/entity_cache.rb
+++ b/app/lib/entity_cache.rb
@@ -16,7 +16,9 @@ class EntityCache
   end
 
   def emoji(shortcodes, domain)
-    shortcodes   = Array(shortcodes)
+    shortcodes = Array(shortcodes)
+    return [] if shortcodes.empty?
+
     cached       = Rails.cache.read_multi(*shortcodes.map { |shortcode| to_key(:emoji, shortcode, domain) })
     uncached_ids = []
 
diff --git a/spec/controllers/concerns/cache_concern_spec.rb b/spec/controllers/concerns/cache_concern_spec.rb
new file mode 100644
index 0000000000..a34d7d7267
--- /dev/null
+++ b/spec/controllers/concerns/cache_concern_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe CacheConcern, type: :controller do
+  controller(ApplicationController) do
+    include CacheConcern
+
+    def empty_array
+      render plain: cache_collection([], Status).size
+    end
+
+    def empty_relation
+      render plain: cache_collection(Status.none, Status).size
+    end
+  end
+
+  before do
+    routes.draw do
+      get  'empty_array' => 'anonymous#empty_array'
+      post 'empty_relation' => 'anonymous#empty_relation'
+    end
+  end
+
+  describe '#cache_collection' do
+    context 'given an empty array' do
+      it 'returns an empty array' do
+        get :empty_array
+        expect(response.body).to eq '0'
+      end
+    end
+
+    context 'given an empty relation' do
+      it 'returns an empty array' do
+        get :empty_relation
+        expect(response.body).to eq '0'
+      end
+    end
+  end
+end
diff --git a/spec/lib/entity_cache_spec.rb b/spec/lib/entity_cache_spec.rb
new file mode 100644
index 0000000000..43494bd92a
--- /dev/null
+++ b/spec/lib/entity_cache_spec.rb
@@ -0,0 +1,19 @@
+require 'rails_helper'
+
+RSpec.describe EntityCache do
+  let(:local_account)  { Fabricate(:account, domain: nil, username: 'alice') }
+  let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') }
+
+  describe '#emoji' do
+    subject { EntityCache.instance.emoji(shortcodes, domain) }
+
+    context 'called with an empty list of shortcodes' do
+      let(:shortcodes) { [] }
+      let(:domain)     { 'example.org' }
+
+      it 'returns an empty array' do
+        is_expected.to eq []
+      end
+    end
+  end
+end

From a4dcaef53b97c58fd153de6f151b6fada40f3442 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 02:42:43 +0100
Subject: [PATCH 12/20] Prepare Mastodon for zeitwerk autoloader (#15917)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Prepare Mastodon for zeitwerk autoloader (Rails 6)

Add inflections and rename/move a few classes.

In particular, app/lib/exceptions.rb and app/lib/sanitize_config.rb
were manually loaded while still in autoload paths.

* Add inflection for Url → URL
---
 app/lib/formatter.rb                                          | 1 -
 app/validators/url_validator.rb                               | 2 +-
 config/application.rb                                         | 3 ++-
 config/initializers/inflections.rb                            | 4 ++++
 db/migrate/20160223165723_add_url_to_statuses.rb              | 2 +-
 db/migrate/20160223165855_add_url_to_accounts.rb              | 2 +-
 .../20160322193748_add_avatar_remote_url_to_accounts.rb       | 2 +-
 .../20170318214217_add_header_remote_url_to_accounts.rb       | 2 +-
 db/migrate/20171130000000_add_embed_url_to_preview_cards.rb   | 2 +-
 .../20180304013859_add_featured_collection_url_to_accounts.rb | 2 +-
 db/migrate/20200529214050_add_devices_url_to_accounts.rb      | 2 +-
 {app/lib => lib}/exceptions.rb                                | 0
 {app/lib => lib/sanitize_ext}/sanitize_config.rb              | 0
 spec/lib/sanitize_config_spec.rb                              | 1 -
 spec/validators/url_validator_spec.rb                         | 2 +-
 15 files changed, 15 insertions(+), 12 deletions(-)
 rename {app/lib => lib}/exceptions.rb (100%)
 rename {app/lib => lib/sanitize_ext}/sanitize_config.rb (100%)

diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 6fb5d54199..2611bcbae0 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 
 require 'singleton'
-require_relative './sanitize_config'
 
 class Formatter
   include Singleton
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb
index d95a03fbf8..f50abbe246 100644
--- a/app/validators/url_validator.rb
+++ b/app/validators/url_validator.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-class UrlValidator < ActiveModel::EachValidator
+class URLValidator < ActiveModel::EachValidator
   def validate_each(record, attribute, value)
     record.errors.add(attribute, I18n.t('applications.invalid_url')) unless compliant?(value)
   end
diff --git a/config/application.rb b/config/application.rb
index 116eaf29d4..0960247b3a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -6,8 +6,9 @@ require 'rails/all'
 # you've limited to :test, :development, or :production.
 Bundler.require(*Rails.groups)
 
-require_relative '../app/lib/exceptions'
+require_relative '../lib/exceptions'
 require_relative '../lib/enumerable'
+require_relative '../lib/sanitize_ext/sanitize_config'
 require_relative '../lib/redis/namespace_extensions'
 require_relative '../lib/paperclip/url_generator_extensions'
 require_relative '../lib/paperclip/attachment_extensions'
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index ebb7541eba..9bc9a54b2d 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -20,6 +20,10 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
   inflect.acronym 'JsonLd'
   inflect.acronym 'NodeInfo'
   inflect.acronym 'Ed25519'
+  inflect.acronym 'TOC'
+  inflect.acronym 'RSS'
+  inflect.acronym 'REST'
+  inflect.acronym 'URL'
 
   inflect.singular 'data', 'data'
 end
diff --git a/db/migrate/20160223165723_add_url_to_statuses.rb b/db/migrate/20160223165723_add_url_to_statuses.rb
index 80f4b3289e..fee7f9c59f 100644
--- a/db/migrate/20160223165723_add_url_to_statuses.rb
+++ b/db/migrate/20160223165723_add_url_to_statuses.rb
@@ -1,4 +1,4 @@
-class AddUrlToStatuses < ActiveRecord::Migration[4.2]
+class AddURLToStatuses < ActiveRecord::Migration[4.2]
   def change
     add_column :statuses, :url, :string, null: true, default: nil
   end
diff --git a/db/migrate/20160223165855_add_url_to_accounts.rb b/db/migrate/20160223165855_add_url_to_accounts.rb
index c81b1c64fc..a4db8814af 100644
--- a/db/migrate/20160223165855_add_url_to_accounts.rb
+++ b/db/migrate/20160223165855_add_url_to_accounts.rb
@@ -1,4 +1,4 @@
-class AddUrlToAccounts < ActiveRecord::Migration[4.2]
+class AddURLToAccounts < ActiveRecord::Migration[4.2]
   def change
     add_column :accounts, :url, :string, null: true, default: nil
   end
diff --git a/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb b/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb
index f9c213d9b4..0792863a37 100644
--- a/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb
+++ b/db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb
@@ -1,4 +1,4 @@
-class AddAvatarRemoteUrlToAccounts < ActiveRecord::Migration[4.2]
+class AddAvatarRemoteURLToAccounts < ActiveRecord::Migration[4.2]
   def change
     add_column :accounts, :avatar_remote_url, :string, null: true, default: nil
   end
diff --git a/db/migrate/20170318214217_add_header_remote_url_to_accounts.rb b/db/migrate/20170318214217_add_header_remote_url_to_accounts.rb
index 0ba38d3e00..20c9659880 100644
--- a/db/migrate/20170318214217_add_header_remote_url_to_accounts.rb
+++ b/db/migrate/20170318214217_add_header_remote_url_to_accounts.rb
@@ -1,4 +1,4 @@
-class AddHeaderRemoteUrlToAccounts < ActiveRecord::Migration[5.0]
+class AddHeaderRemoteURLToAccounts < ActiveRecord::Migration[5.0]
   def change
     add_column :accounts, :header_remote_url, :string, null: false, default: ''
   end
diff --git a/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb b/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb
index d19c0091bc..8fcabef9fd 100644
--- a/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb
+++ b/db/migrate/20171130000000_add_embed_url_to_preview_cards.rb
@@ -1,6 +1,6 @@
 require Rails.root.join('lib', 'mastodon', 'migration_helpers')
 
-class AddEmbedUrlToPreviewCards < ActiveRecord::Migration[5.1]
+class AddEmbedURLToPreviewCards < ActiveRecord::Migration[5.1]
   include Mastodon::MigrationHelpers
 
   disable_ddl_transaction!
diff --git a/db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb b/db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb
index e0b8ed5cc1..1964b51216 100644
--- a/db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb
+++ b/db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb
@@ -1,4 +1,4 @@
-class AddFeaturedCollectionUrlToAccounts < ActiveRecord::Migration[5.1]
+class AddFeaturedCollectionURLToAccounts < ActiveRecord::Migration[5.1]
   def change
     add_column :accounts, :featured_collection_url, :string
   end
diff --git a/db/migrate/20200529214050_add_devices_url_to_accounts.rb b/db/migrate/20200529214050_add_devices_url_to_accounts.rb
index 564877e5dc..1323f8df7e 100644
--- a/db/migrate/20200529214050_add_devices_url_to_accounts.rb
+++ b/db/migrate/20200529214050_add_devices_url_to_accounts.rb
@@ -1,4 +1,4 @@
-class AddDevicesUrlToAccounts < ActiveRecord::Migration[5.2]
+class AddDevicesURLToAccounts < ActiveRecord::Migration[5.2]
   def change
     add_column :accounts, :devices_url, :string
   end
diff --git a/app/lib/exceptions.rb b/lib/exceptions.rb
similarity index 100%
rename from app/lib/exceptions.rb
rename to lib/exceptions.rb
diff --git a/app/lib/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb
similarity index 100%
rename from app/lib/sanitize_config.rb
rename to lib/sanitize_ext/sanitize_config.rb
diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb
index d66302e644..747d81158d 100644
--- a/spec/lib/sanitize_config_spec.rb
+++ b/spec/lib/sanitize_config_spec.rb
@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 
 require 'rails_helper'
-require Rails.root.join('app', 'lib', 'sanitize_config.rb')
 
 describe Sanitize::Config do
   describe '::MASTODON_STRICT' do
diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb
index e8d0e64946..a44878a44f 100644
--- a/spec/validators/url_validator_spec.rb
+++ b/spec/validators/url_validator_spec.rb
@@ -2,7 +2,7 @@
 
 require 'rails_helper'
 
-RSpec.describe UrlValidator, type: :validator do
+RSpec.describe URLValidator, type: :validator do
   describe '#validate_each' do
     before do
       allow(validator).to receive(:compliant?).with(value) { compliant }

From 9aaaa96d2ff5e27f065375a2544e86afa31a4e13 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 02:43:13 +0100
Subject: [PATCH 13/20] Use more robust hook for loading timestamp_id function
 into database (#15919)

---
 config/application.rb                         |  1 +
 ...70920024819_status_ids_to_timestamp_ids.rb |  4 +-
 .../database_tasks_extensions.rb              | 20 +++++++
 lib/tasks/db.rake                             | 56 -------------------
 4 files changed, 23 insertions(+), 58 deletions(-)
 create mode 100644 lib/active_record/database_tasks_extensions.rb

diff --git a/config/application.rb b/config/application.rb
index 0960247b3a..3267fa71be 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -28,6 +28,7 @@ require_relative '../lib/webpacker/manifest_extensions'
 require_relative '../lib/webpacker/helper_extensions'
 require_relative '../lib/action_dispatch/cookie_jar_extensions'
 require_relative '../lib/rails/engine_extensions'
+require_relative '../lib/active_record/database_tasks_extensions'
 
 Dotenv::Railtie.load
 
diff --git a/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb b/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb
index c10aa2c4f7..8679f8ece8 100644
--- a/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb
+++ b/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb
@@ -1,7 +1,7 @@
 class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1]
   def up
     # Prepare the function we will use to generate IDs.
-    Rake::Task['db:define_timestamp_id'].execute
+    Mastodon::Snowflake.define_timestamp_id
 
     # Set up the statuses.id column to use our timestamp-based IDs.
     ActiveRecord::Base.connection.execute(<<~SQL)
@@ -11,7 +11,7 @@ class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1]
     SQL
 
     # Make sure we have a sequence to use.
-    Rake::Task['db:ensure_id_sequences_exist'].execute
+    Mastodon::Snowflake.ensure_id_sequences_exist
   end
 
   def down
diff --git a/lib/active_record/database_tasks_extensions.rb b/lib/active_record/database_tasks_extensions.rb
new file mode 100644
index 0000000000..e274f476df
--- /dev/null
+++ b/lib/active_record/database_tasks_extensions.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require_relative '../mastodon/snowflake'
+
+module ActiveRecord
+  module Tasks
+    module DatabaseTasks
+      original_load_schema = instance_method(:load_schema)
+
+      define_method(:load_schema) do |db_config, *args|
+        ActiveRecord::Base.establish_connection(db_config)
+        Mastodon::Snowflake.define_timestamp_id
+
+        original_load_schema.bind(self).call(db_config, *args)
+
+        Mastodon::Snowflake.ensure_id_sequences_exist
+      end
+    end
+  end
+end
diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake
index f6c9c7eecf..552a02b3f1 100644
--- a/lib/tasks/db.rake
+++ b/lib/tasks/db.rake
@@ -1,36 +1,5 @@
 # frozen_string_literal: true
 
-require_relative '../mastodon/snowflake'
-
-def each_schema_load_environment
-  # If we're in development, also run this for the test environment.
-  # This is a somewhat hacky way to do this, so here's why:
-  # 1. We have to define this before we load the schema, or we won't
-  #    have a timestamp_id function when we get to it in the schema.
-  # 2. db:setup calls db:schema:load_if_ruby, which calls
-  #    db:schema:load, which we define above as having a prerequisite
-  #    of this task.
-  # 3. db:schema:load ends up running
-  #    ActiveRecord::Tasks::DatabaseTasks.load_schema_current, which
-  #    calls a private method `each_current_configuration`, which
-  #    explicitly also does the loading for the `test` environment
-  #    if the current environment is `development`, so we end up
-  #    needing to do the same, and we can't even use the same method
-  #    to do it.
-
-  if Rails.env.development?
-    test_conf = ActiveRecord::Base.configurations['test']
-
-    if test_conf['database']&.present?
-      ActiveRecord::Base.establish_connection(:test)
-      yield
-      ActiveRecord::Base.establish_connection(Rails.env.to_sym)
-    end
-  end
-
-  yield
-end
-
 namespace :db do
   namespace :migrate do
     desc 'Setup the db or migrate depending on state of db'
@@ -61,29 +30,4 @@ namespace :db do
   end
 
   Rake::Task['db:migrate'].enhance(['db:post_migration_hook'])
-
-  # Before we load the schema, define the timestamp_id function.
-  # Idiomatically, we might do this in a migration, but then it
-  # wouldn't end up in schema.rb, so we'd need to figure out a way to
-  # get it in before doing db:setup as well. This is simpler, and
-  # ensures it's always in place.
-  Rake::Task['db:schema:load'].enhance ['db:define_timestamp_id']
-
-  # After we load the schema, make sure we have sequences for each
-  # table using timestamp IDs.
-  Rake::Task['db:schema:load'].enhance do
-    Rake::Task['db:ensure_id_sequences_exist'].invoke
-  end
-
-  task :define_timestamp_id do
-    each_schema_load_environment do
-      Mastodon::Snowflake.define_timestamp_id
-    end
-  end
-
-  task :ensure_id_sequences_exist do
-    each_schema_load_environment do
-      Mastodon::Snowflake.ensure_id_sequences_exist
-    end
-  end
 end

From 55ac2b9c6085def9e692fa69b849239c1249d9fd Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 02:44:57 +0100
Subject: [PATCH 14/20] Add option to opt out of unread notification markers
 (#15842)

Fixes #15133
---
 .../notifications/components/column_settings.js        | 10 ++++++++++
 .../mastodon/features/notifications/index.js           |  4 ++--
 app/javascript/mastodon/reducers/settings.js           |  1 +
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js
index 8339a367eb..0c24c3294a 100644
--- a/app/javascript/mastodon/features/notifications/components/column_settings.js
+++ b/app/javascript/mastodon/features/notifications/components/column_settings.js
@@ -55,6 +55,16 @@ export default class ColumnSettings extends React.PureComponent {
           <ClearColumnButton onClick={onClear} />
         </div>
 
+        <div role='group' aria-labelledby='notifications-unread-markers'>
+          <span id='notifications-unread-markers' className='column-settings__section'>
+            <FormattedMessage id='notifications.column_settings.unread_markers.category' defaultMessage='Unread notification markers' />
+          </span>
+
+          <div className='column-settings__row'>
+            <SettingToggle id='unread-notification-markers' prefix='notifications' settings={settings} settingPath={['showUnread']} onChange={onChange} label={filterShowStr} />
+          </div>
+        </div>
+
         <div role='group' aria-labelledby='notifications-filter-bar'>
           <span id='notifications-filter-bar' className='column-settings__section'>
             <FormattedMessage id='notifications.column_settings.filter_bar.category' defaultMessage='Quick filter bar' />
diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js
index 108470c9a7..cf8fd71277 100644
--- a/app/javascript/mastodon/features/notifications/index.js
+++ b/app/javascript/mastodon/features/notifications/index.js
@@ -60,8 +60,8 @@ const mapStateToProps = state => ({
   isUnread: state.getIn(['notifications', 'unread']) > 0 || state.getIn(['notifications', 'pendingItems']).size > 0,
   hasMore: state.getIn(['notifications', 'hasMore']),
   numPending: state.getIn(['notifications', 'pendingItems'], ImmutableList()).size,
-  lastReadId: state.getIn(['notifications', 'readMarkerId']),
-  canMarkAsRead: state.getIn(['notifications', 'readMarkerId']) !== '0' && getNotifications(state).some(item => item !== null && compareId(item.get('id'), state.getIn(['notifications', 'readMarkerId'])) > 0),
+  lastReadId: state.getIn(['settings', 'notifications', 'showUnread']) ? state.getIn(['notifications', 'readMarkerId']) : '0',
+  canMarkAsRead: state.getIn(['settings', 'notifications', 'showUnread']) && state.getIn(['notifications', 'readMarkerId']) !== '0' && getNotifications(state).some(item => item !== null && compareId(item.get('id'), state.getIn(['notifications', 'readMarkerId'])) > 0),
   needsNotificationPermission: state.getIn(['settings', 'notifications', 'alerts']).includes(true) && state.getIn(['notifications', 'browserSupport']) && state.getIn(['notifications', 'browserPermission']) === 'default' && !state.getIn(['settings', 'notifications', 'dismissPermissionBanner']),
 });
 
diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js
index 357ab352ae..2a89919e1f 100644
--- a/app/javascript/mastodon/reducers/settings.js
+++ b/app/javascript/mastodon/reducers/settings.js
@@ -45,6 +45,7 @@ const initialState = ImmutableMap({
     }),
 
     dismissPermissionBanner: false,
+    showUnread: true,
 
     shows: ImmutableMap({
       follow: true,

From b3582298341e32528929c6f3292e36a6fa261ba5 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 02:45:34 +0100
Subject: [PATCH 15/20] Further preparation for Rails 6 (#15916)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Use ActiveRecord::Result#to_ary instead of deprecated to_hash

They do the same thing, and to_hash has been removed from Rails 6.1

* Explicitly name polymorphic indexes to workaround a bug in Rails 6.1

cf. https://github.com/rails/rails/issues/41693

* Fix incorrect usage of “foreign_key” in migration script

* Use `ActiveModel::Errors#delete` instead of deprecated clear method

* Fix link headers tests on Rails 6.1

Rails 6.1 adds values to the Link header by default, thus it is not a
LinkHeader object anymore. Fix the test to parse the Link header instead
of assuming it is a LinkHeader.
---
 app/controllers/admin/domain_blocks_controller.rb         | 2 +-
 db/migrate/20161006213403_rails_settings_migration.rb     | 8 ++++----
 db/migrate/20171119172437_create_admin_action_logs.rb     | 2 +-
 db/migrate/20180528141303_fix_accounts_unique_index.rb    | 2 +-
 .../20181024224956_migrate_account_conversations.rb       | 4 ++--
 .../20181207011115_downcase_custom_emoji_domains.rb       | 2 +-
 .../20190726175042_add_case_insensitive_index_to_tags.rb  | 2 +-
 lib/mastodon/migration_helpers.rb                         | 6 +++---
 spec/requests/link_headers_spec.rb                        | 2 +-
 9 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb
index ba927b04ad..b140c454c1 100644
--- a/app/controllers/admin/domain_blocks_controller.rb
+++ b/app/controllers/admin/domain_blocks_controller.rb
@@ -22,7 +22,7 @@ module Admin
       if existing_domain_block.present? && !@domain_block.stricter_than?(existing_domain_block)
         @domain_block.save
         flash.now[:alert] = I18n.t('admin.domain_blocks.existing_domain_block_html', name: existing_domain_block.domain, unblock_url: admin_domain_block_path(existing_domain_block)).html_safe # rubocop:disable Rails/OutputSafety
-        @domain_block.errors[:domain].clear
+        @domain_block.errors.delete(:domain)
         render :new
       else
         if existing_domain_block.present?
diff --git a/db/migrate/20161006213403_rails_settings_migration.rb b/db/migrate/20161006213403_rails_settings_migration.rb
index 42875d7cbd..9d565cb5c6 100644
--- a/db/migrate/20161006213403_rails_settings_migration.rb
+++ b/db/migrate/20161006213403_rails_settings_migration.rb
@@ -7,12 +7,12 @@ end
 class RailsSettingsMigration < MIGRATION_BASE_CLASS
   def self.up
     create_table :settings do |t|
-      t.string     :var, :null => false
+      t.string     :var, null: false
       t.text       :value
-      t.references :target, :null => false, :polymorphic => true
-      t.timestamps :null => true
+      t.references :target, null: false, polymorphic: true, index: { name: 'index_settings_on_target_type_and_target_id' }
+      t.timestamps null: true
     end
-    add_index :settings, [ :target_type, :target_id, :var ], :unique => true
+    add_index :settings, [ :target_type, :target_id, :var ], unique: true
   end
 
   def self.down
diff --git a/db/migrate/20171119172437_create_admin_action_logs.rb b/db/migrate/20171119172437_create_admin_action_logs.rb
index 0c2b6c623d..b690735d26 100644
--- a/db/migrate/20171119172437_create_admin_action_logs.rb
+++ b/db/migrate/20171119172437_create_admin_action_logs.rb
@@ -3,7 +3,7 @@ class CreateAdminActionLogs < ActiveRecord::Migration[5.1]
     create_table :admin_action_logs do |t|
       t.belongs_to :account, foreign_key: { on_delete: :cascade }
       t.string :action, null: false, default: ''
-      t.references :target, polymorphic: true
+      t.references :target, polymorphic: true, index: { name: 'index_admin_action_logs_on_target_type_and_target_id' }
       t.text :recorded_changes, null: false, default: ''
 
       t.timestamps
diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb
index 5d7b3c463b..02813f363c 100644
--- a/db/migrate/20180528141303_fix_accounts_unique_index.rb
+++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb
@@ -37,7 +37,7 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
       end
     end
 
-    duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_hash
+    duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary
 
     duplicates.each do |row|
       deduplicate_account!(row['ids'].split(','))
diff --git a/db/migrate/20181024224956_migrate_account_conversations.rb b/db/migrate/20181024224956_migrate_account_conversations.rb
index 12e0a70fac..9e6497d81f 100644
--- a/db/migrate/20181024224956_migrate_account_conversations.rb
+++ b/db/migrate/20181024224956_migrate_account_conversations.rb
@@ -17,8 +17,8 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2]
     belongs_to :account, optional: true
     belongs_to :activity, polymorphic: true, optional: true
 
-    belongs_to :status,         foreign_type: 'Status',        foreign_key: 'activity_id', optional: true
-    belongs_to :mention,        foreign_type: 'Mention',       foreign_key: 'activity_id', optional: true
+    belongs_to :status,  foreign_key: 'activity_id', optional: true
+    belongs_to :mention, foreign_key: 'activity_id', optional: true
 
     def target_status
       mention&.status
diff --git a/db/migrate/20181207011115_downcase_custom_emoji_domains.rb b/db/migrate/20181207011115_downcase_custom_emoji_domains.rb
index 65f1fc8d93..e27e0249d9 100644
--- a/db/migrate/20181207011115_downcase_custom_emoji_domains.rb
+++ b/db/migrate/20181207011115_downcase_custom_emoji_domains.rb
@@ -2,7 +2,7 @@ class DowncaseCustomEmojiDomains < ActiveRecord::Migration[5.2]
   disable_ddl_transaction!
 
   def up
-    duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_hash
+    duplicates = CustomEmoji.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM custom_emojis GROUP BY shortcode, lower(domain) HAVING count(*) > 1').to_ary
 
     duplicates.each do |row|
       CustomEmoji.where(id: row['ids'].split(',')[0...-1]).destroy_all
diff --git a/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb b/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb
index 057fc86baa..eb03d7ca7d 100644
--- a/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb
+++ b/db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb
@@ -2,7 +2,7 @@ class AddCaseInsensitiveIndexToTags < ActiveRecord::Migration[5.2]
   disable_ddl_transaction!
 
   def up
-    Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_hash.each do |row|
+    Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_ary.each do |row|
       canonical_tag_id  = row['ids'].split(',').first
       redundant_tag_ids = row['ids'].split(',')[1..-1]
 
diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb
index bf2314ecb1..fcaa9259e3 100644
--- a/lib/mastodon/migration_helpers.rb
+++ b/lib/mastodon/migration_helpers.rb
@@ -319,7 +319,7 @@ module Mastodon
         count_arel = table.project(Arel.star.count.as('count'))
         count_arel = yield table, count_arel if block_given?
 
-        total = exec_query(count_arel.to_sql).to_hash.first['count'].to_i
+        total = exec_query(count_arel.to_sql).to_ary.first['count'].to_i
 
         return if total == 0
       end
@@ -335,7 +335,7 @@ module Mastodon
 
       start_arel = table.project(table[:id]).order(table[:id].asc).take(1)
       start_arel = yield table, start_arel if block_given?
-      first_row = exec_query(start_arel.to_sql).to_hash.first
+      first_row = exec_query(start_arel.to_sql).to_ary.first
       # In case there are no rows but we didn't catch it in the estimated size:
       return unless first_row
       start_id = first_row['id'].to_i
@@ -356,7 +356,7 @@ module Mastodon
             .skip(batch_size)
 
           stop_arel = yield table, stop_arel if block_given?
-          stop_row = exec_query(stop_arel.to_sql).to_hash.first
+          stop_row = exec_query(stop_arel.to_sql).to_ary.first
 
           update_arel = Arel::UpdateManager.new
             .table(table)
diff --git a/spec/requests/link_headers_spec.rb b/spec/requests/link_headers_spec.rb
index 712ee262b8..c32e0f79a9 100644
--- a/spec/requests/link_headers_spec.rb
+++ b/spec/requests/link_headers_spec.rb
@@ -25,7 +25,7 @@ describe 'Link headers' do
     end
 
     def link_header_with_type(type)
-      response.headers['Link'].links.find do |link|
+      LinkHeader.parse(response.headers['Link'].to_s).links.find do |link|
         link.attr_pairs.any? { |pair| pair == ['type', type] }
       end
     end

From 82caed594c3ad2cafe0c83b814879f30942fe57b Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 11:07:56 +0100
Subject: [PATCH 16/20] Change deduplication order of tootctl maintenance
 fix-duplicates (#15923)

Hopefully fixes #15922

Also update support up to latest database schema version
---
 lib/mastodon/maintenance_cli.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/mastodon/maintenance_cli.rb b/lib/mastodon/maintenance_cli.rb
index 029d42a05a..9f1eaf263a 100644
--- a/lib/mastodon/maintenance_cli.rb
+++ b/lib/mastodon/maintenance_cli.rb
@@ -14,7 +14,7 @@ module Mastodon
     end
 
     MIN_SUPPORTED_VERSION = 2019_10_01_213028
-    MAX_SUPPORTED_VERSION = 2020_12_18_054746
+    MAX_SUPPORTED_VERSION = 2021_03_08_133107
 
     # Stubs to enjoy ActiveRecord queries while not depending on a particular
     # version of the code/database
@@ -142,7 +142,6 @@ module Mastodon
       @prompt.warn 'Please make sure to stop Mastodon and have a backup.'
       exit(1) unless @prompt.yes?('Continue?')
 
-      deduplicate_accounts!
       deduplicate_users!
       deduplicate_account_domain_blocks!
       deduplicate_account_identity_proofs!
@@ -157,6 +156,7 @@ module Mastodon
       deduplicate_media_attachments!
       deduplicate_preview_cards!
       deduplicate_statuses!
+      deduplicate_accounts!
       deduplicate_tags!
       deduplicate_webauthn_credentials!
 

From c31c95ffe4fbf80981a0ee03484d72ee6d75d2ee Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 13:14:40 +0100
Subject: [PATCH 17/20] Remove MySQL-specific code from
 Mastodon::MigrationHelpers (#15924)

Mastodon::MigrationHelpers has been forked from Gitlab a long time ago, but
Mastodon has never supported using a MySQL database.

Removing MySQL support from Mastodon::MigrationHelpers makes it a little easier
to maintain. In particular, it removes code that would need updating with
Rails 6.
---
 lib/mastodon/migration_helpers.rb | 84 ++++++-------------------------
 1 file changed, 14 insertions(+), 70 deletions(-)

diff --git a/lib/mastodon/migration_helpers.rb b/lib/mastodon/migration_helpers.rb
index fcaa9259e3..147642a1cc 100644
--- a/lib/mastodon/migration_helpers.rb
+++ b/lib/mastodon/migration_helpers.rb
@@ -41,42 +41,18 @@
 
 module Mastodon
   module MigrationHelpers
-    # Stub for Database.postgresql? from GitLab
-    def self.postgresql?
-      ActiveRecord::Base.configurations[Rails.env]['adapter'].casecmp('postgresql').zero?
-    end
-
-    # Stub for Database.mysql? from GitLab
-    def self.mysql?
-      ActiveRecord::Base.configurations[Rails.env]['adapter'].casecmp('mysql2').zero?
-    end
-
     # Model that can be used for querying permissions of a SQL user.
     class Grant < ActiveRecord::Base
-      self.table_name =
-        if Mastodon::MigrationHelpers.postgresql?
-          'information_schema.role_table_grants'
-        else
-          'mysql.user'
-        end
+      self.table_name = 'information_schema.role_table_grants'
 
       def self.scope_to_current_user
-        if Mastodon::MigrationHelpers.postgresql?
-          where('grantee = user')
-        else
-          where("CONCAT(User, '@', Host) = current_user()")
-        end
+        where('grantee = user')
       end
 
       # Returns true if the current user can create and execute triggers on the
       # given table.
       def self.create_and_execute_trigger?(table)
-        priv =
-          if Mastodon::MigrationHelpers.postgresql?
-            where(privilege_type: 'TRIGGER', table_name: table)
-          else
-            where(Trigger_priv: 'Y')
-          end
+        priv = where(privilege_type: 'TRIGGER', table_name: table)
 
         priv.scope_to_current_user.any?
       end
@@ -141,10 +117,8 @@ module Mastodon
           'in the body of your migration class'
       end
 
-      if MigrationHelpers.postgresql?
-        options = options.merge({ algorithm: :concurrently })
-        disable_statement_timeout
-      end
+      options = options.merge({ algorithm: :concurrently })
+      disable_statement_timeout
 
       add_index(table_name, column_name, options)
     end
@@ -199,8 +173,6 @@ module Mastodon
 
     # Only available on Postgresql >= 9.2
     def supports_drop_index_concurrently?
-      return false unless MigrationHelpers.postgresql?
-
       version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
 
       version >= 90200
@@ -226,13 +198,7 @@ module Mastodon
       # While MySQL does allow disabling of foreign keys it has no equivalent
       # of PostgreSQL's "VALIDATE CONSTRAINT". As a result we'll just fall
       # back to the normal foreign key procedure.
-      if MigrationHelpers.mysql?
-        return add_foreign_key(source, target,
-                               column: column,
-                               on_delete: on_delete)
-      else
-        on_delete = 'SET NULL' if on_delete == :nullify
-      end
+      on_delete = 'SET NULL' if on_delete == :nullify
 
       disable_statement_timeout
 
@@ -270,7 +236,7 @@ module Mastodon
     # the database. Disable the session's statement timeout to ensure
     # migrations don't get killed prematurely. (PostgreSQL only)
     def disable_statement_timeout
-      execute('SET statement_timeout TO 0') if MigrationHelpers.postgresql?
+      execute('SET statement_timeout TO 0')
     end
 
     # Updates the value of a column in batches.
@@ -487,11 +453,7 @@ module Mastodon
       # If we were in the middle of update_column_in_batches, we should remove
       # the old column and start over, as we have no idea where we were.
       if column_for(table, new)
-        if MigrationHelpers.postgresql?
-          remove_rename_triggers_for_postgresql(table, trigger_name)
-        else
-          remove_rename_triggers_for_mysql(trigger_name)
-        end
+        remove_rename_triggers_for_postgresql(table, trigger_name)
 
         remove_column(table, new)
       end
@@ -521,13 +483,8 @@ module Mastodon
       quoted_old = quote_column_name(old)
       quoted_new = quote_column_name(new)
 
-      if MigrationHelpers.postgresql?
-        install_rename_triggers_for_postgresql(trigger_name, quoted_table,
-                                               quoted_old, quoted_new)
-      else
-        install_rename_triggers_for_mysql(trigger_name, quoted_table,
-                                          quoted_old, quoted_new)
-      end
+      install_rename_triggers_for_postgresql(trigger_name, quoted_table,
+                                             quoted_old, quoted_new)
 
       update_column_in_batches(table, new, Arel::Table.new(table)[old])
 
@@ -685,11 +642,7 @@ module Mastodon
 
       check_trigger_permissions!(table)
 
-      if MigrationHelpers.postgresql?
-        remove_rename_triggers_for_postgresql(table, trigger_name)
-      else
-        remove_rename_triggers_for_mysql(trigger_name)
-      end
+      remove_rename_triggers_for_postgresql(table, trigger_name)
 
       remove_column(table, old)
     end
@@ -844,18 +797,9 @@ module Mastodon
       quoted_pattern = Arel::Nodes::Quoted.new(pattern.to_s)
       quoted_replacement = Arel::Nodes::Quoted.new(replacement.to_s)
 
-      if MigrationHelpers.mysql?
-        locate = Arel::Nodes::NamedFunction
-          .new('locate', [quoted_pattern, column])
-        insert_in_place = Arel::Nodes::NamedFunction
-          .new('insert', [column, locate, pattern.size, quoted_replacement])
-
-        Arel::Nodes::SqlLiteral.new(insert_in_place.to_sql)
-      else
-        replace = Arel::Nodes::NamedFunction
-          .new("regexp_replace", [column, quoted_pattern, quoted_replacement])
-        Arel::Nodes::SqlLiteral.new(replace.to_sql)
-      end
+      replace = Arel::Nodes::NamedFunction
+        .new("regexp_replace", [column, quoted_pattern, quoted_replacement])
+      Arel::Nodes::SqlLiteral.new(replace.to_sql)
     end
 
     def remove_foreign_key_without_error(*args)

From 741d0952b174740e70a09fe6db6862624dfe1e44 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 13:14:57 +0100
Subject: [PATCH 18/20] Improve account counters handling (#15913)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Improve account counters handling

* Use ActiveRecord::Base::sanitize_sql to pass values instead of interpolating them

Keep using string interpolation for `key` as it is safe and using
“ActiveRecord::Base::sanitize_sql_hash_for_assignment” would require stitching
bits of SQL in a way that is not more easily checked for safety.

* Add migration hook to catch PostgreSQL versions earlier than 9.5
---
 app/models/account_stat.rb                    | 42 -------------
 app/models/concerns/account_counters.rb       | 60 ++++++++++++++++++-
 lib/tasks/db.rake                             |  8 ++-
 spec/models/account_stat_spec.rb              | 57 ------------------
 spec/models/concerns/account_counters_spec.rb | 60 +++++++++++++++++++
 5 files changed, 125 insertions(+), 102 deletions(-)
 delete mode 100644 spec/models/account_stat_spec.rb
 create mode 100644 spec/models/concerns/account_counters_spec.rb

diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb
index e70b54d79b..a826a9af3b 100644
--- a/app/models/account_stat.rb
+++ b/app/models/account_stat.rb
@@ -18,46 +18,4 @@ class AccountStat < ApplicationRecord
   belongs_to :account, inverse_of: :account_stat
 
   update_index('accounts#account', :account)
-
-  def increment_count!(key)
-    update(attributes_for_increment(key))
-  rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
-    begin
-      reload_with_id
-    rescue ActiveRecord::RecordNotFound
-      return
-    end
-
-    retry
-  end
-
-  def decrement_count!(key)
-    update(attributes_for_decrement(key))
-  rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique
-    begin
-      reload_with_id
-    rescue ActiveRecord::RecordNotFound
-      return
-    end
-
-    retry
-  end
-
-  private
-
-  def attributes_for_increment(key)
-    attrs = { key => public_send(key) + 1 }
-    attrs[:last_status_at] = Time.now.utc if key == :statuses_count
-    attrs
-  end
-
-  def attributes_for_decrement(key)
-    attrs = { key => [public_send(key) - 1, 0].max }
-    attrs
-  end
-
-  def reload_with_id
-    self.id = self.class.find_by!(account: account).id if new_record?
-    reload
-  end
 end
diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account_counters.rb
index 6e25e1905e..fd3f161ad5 100644
--- a/app/models/concerns/account_counters.rb
+++ b/app/models/concerns/account_counters.rb
@@ -3,6 +3,8 @@
 module AccountCounters
   extend ActiveSupport::Concern
 
+  ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze
+
   included do
     has_one :account_stat, inverse_of: :account
     after_save :save_account_stat
@@ -14,11 +16,65 @@ module AccountCounters
            :following_count=,
            :followers_count,
            :followers_count=,
-           :increment_count!,
-           :decrement_count!,
            :last_status_at,
            to: :account_stat
 
+  # @param [Symbol] key
+  def increment_count!(key)
+    update_count!(key, 1)
+  end
+
+  # @param [Symbol] key
+  def decrement_count!(key)
+    update_count!(key, -1)
+  end
+
+  # @param [Symbol] key
+  # @param [Integer] value
+  def update_count!(key, value)
+    raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key)
+    raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id)
+
+    value = value.to_i
+    default_value = value.positive? ? value : 0
+
+    # We do an upsert using manually written SQL, as Rails' upsert method does
+    # not seem to support writing expressions in the UPDATE clause, but only
+    # re-insert the provided values instead.
+    # Even ARel seem to be missing proper handling of upserts.
+    sql = if value.positive? && key == :statuses_count
+            <<-SQL.squish
+              INSERT INTO account_stats(account_id, #{key}, created_at, updated_at, last_status_at)
+                VALUES (:account_id, :default_value, now(), now(), now())
+              ON CONFLICT (account_id) DO UPDATE
+              SET #{key} = account_stats.#{key} + :value,
+                  last_status_at = now(),
+                  lock_version = account_stats.lock_version + 1,
+                  updated_at = now()
+              RETURNING id;
+            SQL
+          else
+            <<-SQL.squish
+              INSERT INTO account_stats(account_id, #{key}, created_at, updated_at)
+                VALUES (:account_id, :default_value, now(), now())
+              ON CONFLICT (account_id) DO UPDATE
+              SET #{key} = account_stats.#{key} + :value,
+                  lock_version = account_stats.lock_version + 1,
+                  updated_at = now()
+              RETURNING id;
+            SQL
+          end
+
+    sql = AccountStat.sanitize_sql([sql, account_id: id, default_value: default_value, value: value])
+    account_stat_id = AccountStat.connection.exec_query(sql)[0]['id']
+
+    # Reload account_stat if it was loaded, taking into account newly-created unsaved records
+    if association(:account_stat).loaded?
+      account_stat.id = account_stat_id if account_stat.new_record?
+      account_stat.reload
+    end
+  end
+
   def account_stat
     super || build_account_stat
   end
diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake
index 552a02b3f1..7e6c1c8fc5 100644
--- a/lib/tasks/db.rake
+++ b/lib/tasks/db.rake
@@ -19,7 +19,7 @@ namespace :db do
 
   task :post_migration_hook do
     at_exit do
-      unless %w(C POSIX).include?(ActiveRecord::Base.connection.execute('SELECT datcollate FROM pg_database WHERE datname = current_database();').first['datcollate'])
+      unless %w(C POSIX).include?(ActiveRecord::Base.connection.select_one('SELECT datcollate FROM pg_database WHERE datname = current_database();')['datcollate'])
         warn <<~WARNING
           Your database collation is susceptible to index corruption.
             (This warning does not indicate that index corruption has occured and can be ignored)
@@ -29,5 +29,11 @@ namespace :db do
     end
   end
 
+  task :pre_migration_check do
+    version = ActiveRecord::Base.connection.select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
+    abort 'ERROR: This version of Mastodon requires PostgreSQL 9.5 or newer. Please update PostgreSQL before updating Mastodon.' if version < 90_500
+  end
+
+  Rake::Task['db:migrate'].enhance(['db:pre_migration_check'])
   Rake::Task['db:migrate'].enhance(['db:post_migration_hook'])
 end
diff --git a/spec/models/account_stat_spec.rb b/spec/models/account_stat_spec.rb
deleted file mode 100644
index 8adc0d1d63..0000000000
--- a/spec/models/account_stat_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe AccountStat, type: :model do
-  describe '#increment_count!' do
-    it 'increments the count' do
-      account_stat = AccountStat.create(account: Fabricate(:account))
-      expect(account_stat.followers_count).to eq 0
-      account_stat.increment_count!(:followers_count)
-      expect(account_stat.followers_count).to eq 1
-    end
-
-    it 'increments the count in multi-threaded an environment' do
-      account_stat   = AccountStat.create(account: Fabricate(:account), statuses_count: 0)
-      increment_by   = 15
-      wait_for_start = true
-
-      threads = Array.new(increment_by) do
-        Thread.new do
-          true while wait_for_start
-          AccountStat.find(account_stat.id).increment_count!(:statuses_count)
-        end
-      end
-
-      wait_for_start = false
-      threads.each(&:join)
-
-      expect(account_stat.reload.statuses_count).to eq increment_by
-    end
-  end
-
-  describe '#decrement_count!' do
-    it 'decrements the count' do
-      account_stat = AccountStat.create(account: Fabricate(:account), followers_count: 15)
-      expect(account_stat.followers_count).to eq 15
-      account_stat.decrement_count!(:followers_count)
-      expect(account_stat.followers_count).to eq 14
-    end
-
-    it 'decrements the count in multi-threaded an environment' do
-      account_stat   = AccountStat.create(account: Fabricate(:account), statuses_count: 15)
-      decrement_by   = 10
-      wait_for_start = true
-
-      threads = Array.new(decrement_by) do
-        Thread.new do
-          true while wait_for_start
-          AccountStat.find(account_stat.id).decrement_count!(:statuses_count)
-        end
-      end
-
-      wait_for_start = false
-      threads.each(&:join)
-
-      expect(account_stat.reload.statuses_count).to eq 5
-    end
-  end
-end
diff --git a/spec/models/concerns/account_counters_spec.rb b/spec/models/concerns/account_counters_spec.rb
new file mode 100644
index 0000000000..4350496e79
--- /dev/null
+++ b/spec/models/concerns/account_counters_spec.rb
@@ -0,0 +1,60 @@
+require 'rails_helper'
+
+describe AccountCounters do
+  let!(:account) { Fabricate(:account) }
+
+  describe '#increment_count!' do
+    it 'increments the count' do
+      expect(account.followers_count).to eq 0
+      account.increment_count!(:followers_count)
+      expect(account.followers_count).to eq 1
+    end
+
+    it 'increments the count in multi-threaded an environment' do
+      increment_by   = 15
+      wait_for_start = true
+
+      threads = Array.new(increment_by) do
+        Thread.new do
+          true while wait_for_start
+          account.increment_count!(:statuses_count)
+        end
+      end
+
+      wait_for_start = false
+      threads.each(&:join)
+
+      expect(account.statuses_count).to eq increment_by
+    end
+  end
+
+  describe '#decrement_count!' do
+    it 'decrements the count' do
+      account.followers_count = 15
+      account.save!
+      expect(account.followers_count).to eq 15
+      account.decrement_count!(:followers_count)
+      expect(account.followers_count).to eq 14
+    end
+
+    it 'decrements the count in multi-threaded an environment' do
+      decrement_by   = 10
+      wait_for_start = true
+
+      account.statuses_count = 15
+      account.save!
+
+      threads = Array.new(decrement_by) do
+        Thread.new do
+          true while wait_for_start
+          account.decrement_count!(:statuses_count)
+        end
+      end
+
+      wait_for_start = false
+      threads.each(&:join)
+
+      expect(account.statuses_count).to eq 5
+    end
+  end
+end

From db6551ec09cd8f38a9448ba6f4caae56f7a9bb3d Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 12:47:31 +0100
Subject: [PATCH 19/20] Add option to opt out of unread notification markers

Port 55ac2b9c6085def9e692fa69b849239c1249d9fd to glitch-soc
---
 .../notifications/components/column_settings.js        | 10 ++++++++++
 .../flavours/glitch/features/notifications/index.js    |  4 ++--
 app/javascript/flavours/glitch/reducers/settings.js    |  1 +
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js
index e502c3173f..0676963326 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js
@@ -56,6 +56,16 @@ export default class ColumnSettings extends React.PureComponent {
           <ClearColumnButton onClick={onClear} />
         </div>
 
+        <div role='group' aria-labelledby='notifications-unread-markers'>
+          <span id='notifications-unread-markers' className='column-settings__section'>
+            <FormattedMessage id='notifications.column_settings.unread_markers.category' defaultMessage='Unread notification markers' />
+          </span>
+
+          <div className='column-settings__row'>
+            <SettingToggle id='unread-notification-markers' prefix='notifications' settings={settings} settingPath={['showUnread']} onChange={onChange} label={filterShowStr} />
+          </div>
+        </div>
+
         <div role='group' aria-labelledby='notifications-filter-bar'>
           <span id='notifications-filter-bar' className='column-settings__section'>
             <FormattedMessage id='notifications.column_settings.filter_bar.category' defaultMessage='Quick filter bar' />
diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js
index 5ceda9a91c..842e023711 100644
--- a/app/javascript/flavours/glitch/features/notifications/index.js
+++ b/app/javascript/flavours/glitch/features/notifications/index.js
@@ -67,8 +67,8 @@ const mapStateToProps = state => ({
   hasMore: state.getIn(['notifications', 'hasMore']),
   numPending: state.getIn(['notifications', 'pendingItems'], ImmutableList()).size,
   notifCleaningActive: state.getIn(['notifications', 'cleaningMode']),
-  lastReadId: state.getIn(['local_settings', 'notifications', 'show_unread']) ? state.getIn(['notifications', 'readMarkerId']) : '0',
-  canMarkAsRead: state.getIn(['local_settings', 'notifications', 'show_unread']) && state.getIn(['notifications', 'readMarkerId']) !== '0' && getNotifications(state).some(item => item !== null && compareId(item.get('id'), state.getIn(['notifications', 'readMarkerId'])) > 0),
+  lastReadId: state.getIn(['settings', 'notifications', 'showUnread']) ? state.getIn(['notifications', 'readMarkerId']) : '0',
+  canMarkAsRead: state.getIn(['settings', 'notifications', 'showUnread']) && state.getIn(['notifications', 'readMarkerId']) !== '0' && getNotifications(state).some(item => item !== null && compareId(item.get('id'), state.getIn(['notifications', 'readMarkerId'])) > 0),
   needsNotificationPermission: state.getIn(['settings', 'notifications', 'alerts']).includes(true) && state.getIn(['notifications', 'browserSupport']) && state.getIn(['notifications', 'browserPermission']) === 'default' && !state.getIn(['settings', 'notifications', 'dismissPermissionBanner']),
 });
 
diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
index 091b8feecf..a53d34a83d 100644
--- a/app/javascript/flavours/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -49,6 +49,7 @@ const initialState = ImmutableMap({
     }),
 
     dismissPermissionBanner: false,
+    showUnread: true,
 
     shows: ImmutableMap({
       follow: true,

From 3b7b607300d662aa1f25d459ca12aec89ab550e8 Mon Sep 17 00:00:00 2001
From: Claire <claire.github-309c@sitedethib.com>
Date: Fri, 19 Mar 2021 13:33:46 +0100
Subject: [PATCH 20/20] Migrate glitch-soc local notification settings to
 upstream system

---
 app/javascript/flavours/glitch/actions/store.js | 17 ++++++++++++++++-
 .../features/local_settings/page/index.js       |  8 --------
 .../flavours/glitch/reducers/local_settings.js  |  1 -
 3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/app/javascript/flavours/glitch/actions/store.js b/app/javascript/flavours/glitch/actions/store.js
index 34dcafc510..9dbc0b2148 100644
--- a/app/javascript/flavours/glitch/actions/store.js
+++ b/app/javascript/flavours/glitch/actions/store.js
@@ -1,6 +1,7 @@
 import { Iterable, fromJS } from 'immutable';
 import { hydrateCompose } from './compose';
 import { importFetchedAccounts } from './importer';
+import { saveSettings } from './settings';
 
 export const STORE_HYDRATE = 'STORE_HYDRATE';
 export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY';
@@ -9,9 +10,22 @@ const convertState = rawState =>
   fromJS(rawState, (k, v) =>
     Iterable.isIndexed(v) ? v.toList() : v.toMap());
 
+const applyMigrations = (state) => {
+  return state.withMutations(state => {
+    // Migrate glitch-soc local-only “Show unread marker” setting to Mastodon's setting
+    if (state.getIn(['local_settings', 'notifications', 'show_unread']) !== undefined) {
+      // Only change if the Mastodon setting does not deviate from default
+      if (state.getIn(['settings', 'notifications', 'showUnread']) !== false) {
+        state.setIn(['settings', 'notifications', 'showUnread'], state.getIn(['local_settings', 'notifications', 'show_unread']));
+      }
+      state.removeIn(['local_settings', 'notifications', 'show_unread'])
+    }
+  });
+};
+
 export function hydrateStore(rawState) {
   return dispatch => {
-    const state = convertState(rawState);
+    const state = applyMigrations(convertState(rawState));
 
     dispatch({
       type: STORE_HYDRATE,
@@ -20,5 +34,6 @@ export function hydrateStore(rawState) {
 
     dispatch(hydrateCompose());
     dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
+    dispatch(saveSettings());
   };
 };
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
index 3af6cbdf61..45d10d154e 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js
@@ -113,14 +113,6 @@ class LocalSettingsPage extends React.PureComponent {
             <FormattedMessage id='settings.notifications.favicon_badge' defaultMessage='Unread notifications favicon badge' />
             <span className='hint'><FormattedMessage id='settings.notifications.favicon_badge.hint' defaultMessage="Add a badge for unread notifications to the favicon" /></span>
           </LocalSettingsPageItem>
-          <LocalSettingsPageItem
-            settings={settings}
-            item={['notifications', 'show_unread']}
-            id='mastodon-settings--notifications-show_unread'
-            onChange={onChange}
-          >
-            <FormattedMessage id='settings.notifications.show_unread' defaultMessage='Show unread marker' />
-          </LocalSettingsPageItem>
         </section>
         <section>
           <h2><FormattedMessage id='settings.layout_opts' defaultMessage='Layout options' /></h2>
diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js
index ea37ae4aa6..c115cad6ba 100644
--- a/app/javascript/flavours/glitch/reducers/local_settings.js
+++ b/app/javascript/flavours/glitch/reducers/local_settings.js
@@ -55,7 +55,6 @@ const initialState = ImmutableMap({
   notifications : ImmutableMap({
     favicon_badge : false,
     tab_badge     : true,
-    show_unread   : true,
   }),
 });